Helve’s Python memo

Pythonを使った機械学習やデータ分析の備忘録

<BeautifulSoup> XMLの解析

BeautifulSoupを使って、XMLを解析(parse)する。

目次

環境

python 3.6.1
beautifulsoup4 4.6.0
lxml 3.8.0

インストール

$ pip install beautifulsoup4
$ pip install lxml

XMLの構文

XMLの構造について、以下の名称を用いる。

<要素名 属性="値">内容</要素名>

扱うXMLファイル

今回、書籍データを模擬した以下のXMLファイルを読み込む。
ファイルはローカルに置かれているものとする。
オンラインのファイルを取得するときは、requestやurllibを使う。

doc.xml
<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ファイルオブジェクトをBeautifulSoupでパースする。
BeautifulSoupで使用できるパーサを次表に示す。今回はxmlパーサを使用する。

html.parser 標準ライブラリのパーサ
lxml lxmlライブラリのHTMLパーサ。処理が高速
lxml-xml または xml lxmlライブラリのXMLパーサ。処理が高速
html5lib HTML5に対応

>>> from bs4 import BeautifulSoup
>>> with open("doc.xml") as doc:
...     soup = BeautifulSoup(doc, "xml") # 第2引数でパーサを指定
>>> 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の探索

要素の検索

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
<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>

参考:
Beautiful Soup Documentation — Beautiful Soup 4.4.0 documentation