はじめに #
BeautifulSoupを使ってXMLを解析(parse)します。
環境 #
2020-11-07: 以下の環境で検証しました。
- Python 3.7.4
- beautifulsoup4 4.8.0
- lxml 4.4.1
2025-10-13追記: 以下の環境でも検証しました。
- Python 3.13.7
- beautifulsoup4 4.14.2
- lxml 6.0.2
インストール #
ターミナルで以下のコマンドを実行し、beautifulsoup4
とlxml
をインストールします。
pip install beautifulsoup4 lxml
uv の場合は以下になります。
uv add beautifulsoup4 lxml
XMLの構文 #
この記事では、XMLの構造について以下の名称を用います。
<要素名 属性="値">内容</要素名>
扱うXMLファイル #
書籍データを模擬したXMLファイルを扱います。
以下のXMLにdoc.xml
と名前を付けて、作業ディレクトリに置いていることを前提とします。
また、文字エンコーディングはUTF-8として下さい。
<data>
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>
<book id="002">
<title language="Japanese">羅生門</title>
<author autonym="芥川龍之介">芥川龍之介</author>
<genre>小説</genre>
</book>
<book id="003">
<title language="Japanese">柿の種</title>
<author autonym="寺田寅彦">寺田寅彦</author>
<genre>随筆</genre>
</book>
</data>
“autonym"は「本名」の意味です。 また、この記事では扱いませんが、requestやurllibなどのライブラリを使うと、インターネット上のXMLファイルを自動で収集できます。
XMLファイルのパース #
読み込んだXMLファイルオブジェクトをBeautifulSoupでパースします。 BeautifulSoupで使用できるパーサを次表に示します。 今回はlxmlパーサを使用します。
パーサ | 説明 |
---|---|
html.parser | 標準ライブラリのパーサ |
lxml | lxmlライブラリのHTMLパーサ。処理が高速 |
lxml-xml または xml | lxmlライブラリのXMLパーサ。処理が高速 |
html5lib | HTML5に対応 |
以下のようにBeautifulSoupをインポートして、XMLファイルとパーサを引数に指定します。
BeautifulSoup
オブジェクトのsoup
をptint
文で出力すると、XMLが表示されます。
>>> from bs4 import BeautifulSoup
>>> with open("doc.xml", encoding="utf-8") as f:
... soup = BeautifulSoup(f, features="xml") # featuresでパーサを指定
>>> print(soup)
<?xml version="1.0" encoding="utf-8"?>
<data>
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>
<book id="002">
<title language="Japanese">羅生門</title>
<author autonym="芥川龍之介">芥川龍之介</author>
<genre>小説</genre>
</book>
<book id="003">
<title language="Japanese">柿の種</title>
<author autonym="寺田寅彦">寺田寅彦</author>
<genre>随筆</genre>
</book>
</data>
XMLが文字化けする場合はopen時のencodingを見直して下さい。
また、prettify()
メソッドを使うとインデントで整形されたXMLが表示されます。
>>> print(soup.prettify())
<?xml version="1.0" encoding="utf-8"?>
<data>
<book id="001">
<title language="English">
Alice in Wonderland
</title>
<author autonym="Charles Lutwidge Dodgson">
Lewis Carroll
</author>
<genre>
小説
</genre>
</book>
<book id="002">
<title language="Japanese">
羅生門
</title>
<author autonym="芥川龍之介">
芥川龍之介
</author>
<genre>
小説
</genre>
</book>
<book id="003">
<title language="Japanese">
柿の種
</title>
<author autonym="寺田寅彦">
寺田寅彦
</author>
<genre>
随筆
</genre>
</book>
</data>
パースしたXMLの探索 #
要素の検索 #
以下のメソッドをXML内の要素の探索に利用できます。
メソッド | 説明 |
---|---|
find() |
要素名または属性で検索し、該当する最初の要素を返す |
find_all() |
要素名または属性で検索し、該当する全ての要素を返す |
使用例は次の通り。
>>> soup.find("book") # 最初の"book"要素
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>
>>> soup.book # ".要素"でも同じ結果になる
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>
>>> soup.find(language="Japanese") # language属性がJapaneseである最初の要素
<title language="Japanese">羅生門</title>
>>> soup.find_all("author") # 全てのauthor要素
[<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>,
<author autonym="芥川龍之介">芥川龍之介</author>,
<author autonym="寺田寅彦">寺田寅彦</author>]
>>> soup.find_all(language="Japanese") # language属性がJapaneseである全ての要素
[<title language="Japanese">羅生門</title>,
<title language="Japanese">柿の種</title>]
属性と値の取得 #
属性から値を取得する場合は[ ]
で属性を指定します。
全ての属性と値を取得する場合はattrs
メンバを使います。
>>> title001 = soup.book.title
>>> print(title001)
<title language="English">Alice in Wonderland</title>
>>> title001["language"] # 属性を指定
'English'
>>> title001.attrs # 属性と値を辞書型で表示
{'language': 'English'}
内容の取得 #
内容を持つ直上の要素まで移動し、string
メンバを使います。
>>> title001 = soup.book.title
>>> print(title001)
<title language="English">Alice in Wonderland</title>
>>> title001.string # 内容を取得
"Alice in Wonderland"
要素間の移動 #
メンバ | 説明 |
---|---|
next_sibling |
同じ階層の次の要素に移動 |
previous_sibling |
同じ階層の前の要素に移動 |
parent |
上の階層の要素に移動 |
>>> book001 = soup.book
>>> print(book001)
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>
>>> author001 = book001.author
>>> print(author001)
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
>>> author001.next_sibling # 改行(\n)も要素に含まれる
'\n'
>>> author001.next_sibling.next_sibling # 次の要素
<genre>小説</genre>
>>> author001.previous_sibling.previous_sibling # 前の要素
<title language="English">Alice in Wonderland</title>
>>> author001.parent # 上の要素
<book id="001">
<title language="English">Alice in Wonderland</title>
<author autonym="Charles Lutwidge Dodgson">Lewis Carroll</author>
<genre>小説</genre>
</book>