ライブラリ: BeautifulSoup

Pythonの BeautifulSoup というライブラリについてご紹介します。

import BeautifulSoup

BeautifulSoup はバージョン 3 までと現在最新のバージョン 4 とでパッケージ名が異なります。バージョン 4 では BeautifulSoup4 もしくは bs4 という名前になっています。

  • バージョン 3: BeautifulSoup
  • バージョン 4: bs4

今回はバージョン 3 を対象に述べていきます。ちなみに、バージョン 3 は Pyton 3 には対応していないため、 Python 3 で使うなら バージョン 4 の方を使うことになります。

バージョン 3 までの BeautifulSoup には大きく分けて 2 つのクラスが入っています。 BeautifulSoupBeautifulStoneSoup です。

  • BeautifulSoup: HTML 用
  • BeautifulStoneSoup: XML 用

(ちなみに、BeautifulSoupのバージョン4では BeautifulStoneSoupBeautifulSoup に吸収され存在しません)。

基本的な使い方は HTML でも XML でも共通なので、今回は ElementTree との対比で後者の BeautifulStoneSoup の方だけを見ていきます。

XMLファイルの読み込み

from BeautifulSoup import BeautifulStoneSoup

XMLFILE = 'sample.xml'

f = open(XMLFILE, 'r')
soup = BeautifulStoneSoup(f.read())
f.close()

XML ファイルを読み込むには、通常のファイルオープンをしてテキストを抽出し、そこから BeautifulStoneSoup インスタンスを生成します。

以下、 samle.xml の中身は次のとおりという想定で進めます。

<post attrA="value A" attrB="value B">
    <title>This is a title.</title>
    <categories>
        <!-- This is a comment. -->
        <category term="Asia"/>
        <category term="South America"/>
        <category term="Europe"/>
    </categories>
</post>

データの読み方

上のコードのとおり XML のおおもとのインスタンス soup を生成したら、あとはツリーを辿ってデータを見ていきます。ツリーを辿るには主に次のふたつのメソッドを使います。

  • soup.find()
  • soup.findall()

BeutifulStoneSoup では各ノードを Tag クラスのインスタンスとして保持します。各ノードの情報にアクセスするには主に次のアトリビュート・メソッドを使います。

  • tag.name
  • tag.string
  • tag.attrs
  • tag.get()

以下、いろいろ見ていきます。

print soup.__class__.__name__
# BeautifulStoneSoup と出力

上のコードで生成したsoupはBeautifulStoneSoupのインスタンスです。

print soup.find('category').__class__.__name__
print soup.find('category').name
print soup.find('category').get('term')
print soup.find('category').attrs
# 以下のとおり出力
# Tag
# category
# Asia
# [(u'term', u'Asia')]

tag.find(タグ名) で子孫のノードにアクセスすることができます。各タグは Tag クラスのインスタンスです。 name にはそのタグ名が入っています。

get()attrs でタグのアトリビュート情報にアクセスできます。読み出した文字列はすべてユニコードとなっています。

print soup.find('title').string
# 以下のとおり出力
# This is a title.

tag.string にはそのタグ内の文字列が入っています。

es = soup.findAll('category')
for e in es:
    print e.name, e.get('term')
# 以下のとおり出力
# category Asia
# category South America
# category Europe

tag.find(タグ名) が最初に見つかった要素を 1 つだけ返すのに対し、 tag.findAll(タグ名) は引っかかった要素をすべて返します。

es = soup.findAll('category', term='Europe')
for e in es:
    print e.name, e.get('term')
# 以下のとおり出力
# category Europe

find() findAll() を使うときは、タグ名だけでなくアトリビュートも手がかりに検索することができます。この例ではアトリビュート term の値が Europe の要素を検索しています。

print soup.post.title.string
# 以下のとおり出力
# This is a title.

タグの親子関係をもとにデータを取得することも可能です。この例では soup 以下の post タグの中にある一番最初の title タグの中身を取得しています。

その他の機能

# 整形表示
print soup.prettify()

取得した XML を整形して表示するために、 prettify() というメソッドが用意されています。

# 元データのエンコード
print soup.originalEncoding

元データの文字コードは、 originalEncoding で確認することができます。

# 子要素を取得
print soup.post.categories.contents
# 以下のとおり出力
# [u'\n', u' This is a comment. ', u'\n', <category term="Asia"></category>, <category term="South America"></category>, <category term="Europe"></category>]

contents を使えば、タグだけでなく、コメントなどの文字列も含めて子要素を取得することができます。ただ、元の XML データに空白や改行が入っていると、思わぬところでインデックスが変わってしまったりしてハマりがちですので、タグ要素だけに着目するのであれば、 find() findAll() などを使うのがよいかと思います。

以上です。

今回は取り上げませんでしたが、このほかにも BeautifulSoup には

  • あるノードの隣のノードや親ノードを取得する機能
  • XMLを編集する機能

なども備わっています。さらに詳しくは参考ページなどをご参照ください。

また、 BeautifulSoup のバージョン 3 までとバージョン 4 とでは互換性の無いところがあるのでその点にも注意が必要です。本記事の説明はバージョン 3 を対象としています。

インストール

pip が入っていれば、コマンドラインから pip install beautifulsoup でインストールできます( BeautifulSoup4 は pip install beautifulsoup4 です)。

参考