Beautiful SoupでHTMLやXMLをparseしよう

Beautiful SoupはHTMLやXMLをparseしてくれるパーサーライブラリです。でも、Beautiful Soupは単なるパーサーじゃなくてちょっと賢い奴なんです。

今回、このBeautiful Soupのドキュメントを翻訳しました。

http://www.tdoc.info/beautifulsoup/

下に軽く紹介していますが、詳しくはこのドキュメントをご覧ください。

Beautiful Soupをざっくり紹介

Beautiful Soupがどういうやつかって?例えばこんなHTMLがあったとしましょう。

<HTML>
<body>

改行<br>
したいよね
<br/>
<! --あれ、空白が入ってるちょっと変なコメント-->
<p>
bodyが閉じてないよ?
</html>

結構変なHTMLですよね。でも、巷にはこういうのも結構あるんです。で、これをtest1.htmlだとします。これをこんな感じのスクリプトでパースしてみると、

soup = BeautifulSoup(open("test1.html"))
print soup.prettify()

こうなります。

<html>
 <body>
  改行
  <br />
  したいよね
  <br />
  <!--あれ、空白が入ってるちょっと変なコメント-->
  <p>
   bodyが閉じてないよ?
  </p>
 </body>
</html>

他にも、

<html>
<form>
 <table>
 <td><input name="input1">一行目二列目
 <tr><td>二行目
 </form>あれ、テーブル閉じてないよ?
 <td>こっちは?
</html>

<html>
 <form>
  <table>
   <td>
    <input name="input1" />
    一行目二列目
   </td>
   <tr>
    <td>
     二行目
    </td>
   </tr>
  </table>
 </form>
 あれ、テーブル閉じてないよ?
 <td>
  こっちは?
 </td>
</html>

という感じにしてくれます。

インストール

ふつーpipですよねー。

% pip install beautifulsoup

使い方

まずはimportします。

from BeautifulSoup import BeautifulSoup          # HTMLの場合こっち
from BeautifulSoup import BeautifulStoneSoup     # XMLの場合こっち
import BeautifulSoup # 全部の場合これ

その後、BeautifulSoupコンストラクタを作って、あとはこれを使います。

soup = BeautifulSoup(html_string)

タグを検索

例えば、こういうHTMLドキュメントがあったとします。

<html>
<h1>H1です</h1>
段落
<p>
ですよ<br/>
</p>
<table>
<tr id="tr-1">閉じてないけどtr-1です<td>td-1-1</td><td>td-1-2
<tr id="tr-2">tr-2です<td class="td">td-2-1</td><td>td-3
</html>

タグはタグの名前で検索できますし、nextSiblingとかを使って順々にたどることも出来ます。もちろんforで回すことも出来ます。

parentで上に、contentsで下に、nextSiblingとprevSiblingで同じ階層にたどる、という感じでしょうか。

soup = BeautifulSoup(doc)
print(soup.h1) # h1を表示
print("-------------------------------")
print(soup.table.td) # <table><td>の最初を表示
print("-------------------------------")
print(soup.table.tr) # <table><tr>の最初表示
print("-------------------------------")
tr1 = soup.table.tr
print(tr1.nextSibling) # tr-1のnextSibling
print("-------------------------------")
print(tr1.nextSibling["id"]) # tr-2のid属性
print("-------------------------------")
print(tr1.nextSibling.contents[1]["class"]) # tr-2の子のtdのclass属性
print("-------------------------------")

とすると、こう出ます。

<h1>H1です</h1>
-------------------------------
<td>td-1-1</td>
-------------------------------
<tr id="tr-1">閉じてないけどtr-1です<td>td-1-1</td><td>td-1-2
</td></tr>
-------------------------------
<tr id="tr-2">tr-2です<td class="td">td-2-1</td><td>td-3
</td></tr>
-------------------------------
tr-2
-------------------------------
td

検索

パースしたツリーを検索できます。

print(soup.findAll('td')) # tdを全部見つけてきます。
print("-------------------------------")
import re
print(soup.findAll(re.compile('^t'))) # tで始まるタグを全部持ってきます
print("-------------------------------")
[<td>td-1-1</td>, <td>td-1-2
</td>, <td class="td">td-2-1</td>, <td>td-3
</td>]
-------------------------------
[<table>
<tr id="tr-1">閉じてないけどtr-1です<td>td-1-1</td><td>td-1-2
</td></tr><tr id="tr-2">tr-2です<td class="td">td-2-1</td><td>td-3
</td></tr></table>, <tr id="tr-1">閉じてないけどtr-1です<td>td-1-1</td><td>td-1-2
</td></tr>, <td>td-1-1</td>, <td>td-1-2
</td>, <tr id="tr-2">tr-2です<td class="td">td-2-1</td><td>td-3
</td></tr>, <td class="td">td-2-1</td>, <td>td-3
</td>]
-------------------------------

他にも

Beautiful Soupはこんなこともできます。

  • 属性の値を入れ替えたり、新しい属性を付けたりする
  • あるエレメントを別なエレメントに置き換える
  • UnicodeDammitというクラスを使ってエンコーディングを判定する
  • HTMLの実体参照を対応するユニコード文字に変換する

詳しくは翻訳したドキュメントを参照してください。