PythonでXMLを読み込み、解析(Parser)する方法

スポンサーリンク


重要な値を取得するために解析が必要なXMLファイルに悩まされたことはありませんか?PythonのXMLパーサを作る方法を学びましょう。

<page>
    <header>
        <type heading="XML Parsing in Python"/>
        <type text="Hello from Python. We'll be parsing XML"/>
    </header>
</page>

Pythonを使ってどのようにXMLファイルを解析し、関連する属性や値を取得するかを見ていきます。

さっそく始めてみましょう。

スポンサーリンク

方法1:ElementTreeを使う(推奨)

このタスクを達成するために、ElementTree Python ライブラリを使用することができます

このライブラリはデフォルトでPythonにバンドルされているため、Python XMLパーサーを構築するための最もシンプルで推奨される方法です。

すでにインストールされているため、アクセスが容易なだけでなく、非常に高速です。

それでは、テストファイルからどのように属性を抽出するかを見てみましょう。

<page>
    <header>
        <type heading="XML Parsing in Python"/>
        <type text="Hello from Python. We'll be parsing XML"/>
    </header>
</page>

ここでは、コアパッケージである xml に含まれる xml.etree.ElementTree というインターフェイスを使用します。

import xml.etree.ElementTree as ET

Python XML Parser Tree の構築

まず、このパースツリーのルートノードを構築しましょう。

これはツリーの最上位ノードで、パージングを開始するために必要です。

ありがたいことに、このAPIにはすでに以下のメソッドが用意されています。

import xml.etree.ElementTree as ET
root_node = ET.parse('sample.xml').getroot()
print(root_node)

これは自動的にXML入力ファイルを読み込んで、ルートノードを取得します。

結果は以下の通りです。

<Element 'page' at 0x7f885836b2f0>

さて、どうやらパースされたようです。

しかし、まだ確認することができません。

そこで、他の属性をパースしてその値を取得することを試みましょう。

関連する属性の値を取得する

それでは、Python XML Parserを使って <heading> 属性の値を取得しましょう。

ルートノード <page> からの位置は <header type=""> なので、そのレベルでマッチしたものをすべてループさせる必要があります。

そのためには、 root_node.findall(level) を使用します。

level は希望する位置(この例では <header type="">) を指定します。

for tag in root_node.find_all(level):
    value = tag.get(attribute)
    if value is not None: print(value)

タグ.get(attribute)は、検索対象のレベルにあるタグの値を取得します。

つまり、

でこれを行い、` 属性の値を取得すればいいのです。

以上です。

import xml.etree.ElementTree as ET
 
# We're at the root node (<page>)
root_node = ET.parse('sample.xml').getroot()
 
# We need to go one level below to get <header>
# and then one more level from that to go to <type>
for tag in root_node.findall('header/type'):
    # Get the value of the heading attribute
    h_value = tag.get('heading')
    if h_value is not None:
        print(h_value)
    # Get the value of the text attribute
    t_value = tag.get('text')
    if t_value is not None:
        print(t_value)

結果は以下の通りです。

XML Parsing in Python
Hello from Python. We'll be parsing XML

XML 解析ツリーのそのレベルにあるすべての値を取得することができました。

XML ファイルの解析に成功しました。

すべてを明らかにするために、別の例を挙げましょう。

ここでは、XML ファイルが次のようなものであると仮定します。

<data>
    <items>
        <item name="item1">10</item>
        <item name="item2">20</item>
        <item name="item3">30</item>
        <item name="item4">40</item>
    </items>
</data>

ここでは、nameの属性値を取得するだけでなく、そのレベルのすべての要素について、テキストの値10、20、30、40を取得する必要があります。

nameの属性値を取得するためには、先ほどと同じようにすればよい。

また、tag.attrib[name]を使用して値を取得することもできます。

これはtag.get(name)` と同じですが、辞書検索を利用する点が異なります。

attr_value = tag.get(attr_name)
# Both methods are the same. You can
# choose any approach
attr_value = tag.attrib[attr_name]

テキストの値を取得するのは簡単です。

を使って取得するだけです。

tag.text

というわけで、このパーサーの完全なプログラムは次のようになります。

import xml.etree.ElementTree as ET
 
# We're at the root node (<page>)
root_node = ET.parse('sample.xml').getroot()
 
# We need to go one level below to get <items>
# and then one more level from that to go to <item>
for tag in root_node.findall('items/item'):
    # Get the value from the attribute 'name'
    value = tag.attrib['name']
    print(value)
    # Get the text of that tag
    print(tag.text)

結果は以下の通りです。

item1
10
item2
20
item3
30
item4
40

このロジックを何段階にも拡張して、任意の長さの XML ファイルを作成することもできます。

また、別の XML ファイルに新しい解析ツリーを書き込むこともできます。

しかし、これはドキュメントを読んでいただければわかると思いますので、出発点を提供します。

方法2: BeautifulSoup を使う (信頼できる)

これも、何らかの理由でソースのXMLの書式が悪い場合に有効な方法です。

XMLは、ファイルに何らかの前処理を施さないと、あまりうまく動作しないことがあります。

BeautifulSoupはこのような種類のファイルに対して非常にうまく動作することが分かっているので、あらゆる種類のXMLファイルをパースしたい場合は、この方法を使用します。

インストールするには、pipを使用して、bs4モジュールをインストールしてください。

pip3 install bs4

前回のXMLファイルに対する小さなスニペットをお見せしましょう。

<data>
    <items>
        <item name="item1">10</item>
        <item name="item2">20</item>
        <item name="item3">30</item>
        <item name="item4">40</item>
    </items>
</data>

このファイルを渡して、bs4 を使ってパースします。

from bs4 import BeautifulSoup
 
fd = open('sample.xml', 'r')
 
xml_file = fd.read()
 
soup = BeautifulSoup(xml_file, 'lxml')
 
for tag in soup.findAll("item"):
    # print(tag)
    print(tag["name"])
    print(tag.text)
 
fd.close()

構文は xml モジュールと似ているので、 value = tag['attribute_name']text = tag.text を使って属性名を取得しています。

前と全く同じです。

結果は以下の通りです。

item1
10
item2
20
item3
30
item4
40

これで、bs4もパースできるようになりました。

もし、ソースとなるXMLファイルのフォーマットが悪い場合は、BeautifulSoupがそのようなファイルを扱うための異なるルールを持っているので、この方法をお勧めします。

まとめ

Python XMLパーサを簡単に作る方法を理解していただけたでしょうか。

2つのアプローチを紹介しました。

1つは xml モジュールを使用する方法、もう1つは BeautifulSoup を使用する方法です。

タイトルとURLをコピーしました