BeautifulSoupの簡単な紹介。
w3mから、rawdogが出力したHTMLの既読管理を行うためのCGIをPythonで記述した際に、
BeautilfSoupというかなり高機能なHTML/XMLパーサを利用しました。
その際に結構色々調べたので、備忘録として。
まずはhttp://www.crummy.com/software/BeautifulSoup:公式サイトからダウンロードしてきます。
普通はpythonのライブラリに展開するとかしますが、私の場合は使いたい場所だけに利用するような感じで。
cd ~/bin tar zxf BeautifulSoup.tar.gz
とでもします。次に、利用したいプログラムの最初の方で
from BeautifulSoup import BeautifulSoup
とします。これで準備が完了しました。
次のようにして利用できます。
soup = BeautifulSoup(open("hoge.html")) soup("a")
BeautifulSoup.BeautifulSoupには、ファイル名の他、ファイル風オブジェクトも渡すことができます。
つまり、urllib.urlopenなどから直接解析することができます。
soup("a")からは、この例ではhoge.htmlから読みだしたHTML中から、aタグを全て抽出してリストとして返します。
他のタグでも同様にして、全部抽出することができます。
soup("a", {"href" : "/"}) # hrefが/であるaタグのみ抽出する soup("a", {"href" : re.compile("^http://")}) # hrefの先頭がhttp://であるaタグのみを抽出する soup("div", {"id" : "foobar", "class" : re.compile("^hoge")}) # idがfoobarであり、かつclassの先頭がhogeであるdiv
更に、オプションとして辞書を渡すと、その条件に合致するタグだけを抽出します。例でも挙げているように、なんと正規表現まで渡せます。
ちなみにsoup()は、soup.get()を呼びだしているのと同義ですので、上の例はすべてsoup.get()でも呼びだせます。
soup()から取得できるリストの中身は、各タグのオブジェクト表現したものです。そのまま文字列として評価すると、
自身のタグまで付与されたままで表示されてしまいます。
自身のタグの中身のみを出力する場合には、renderContentsを使います。
また、それぞれのタグの属性は、エレメントオブジェクトを辞書としてアクセスすると取得/変更することができます。
a = open("hoge.html") ; a.write('<b class="i">foobar</b>'); a.close() soup = BeautifulSoup("hoge.html") soup("b")[0] --> ['<b>foobar</b>'] soup("b")[0]["class"] --> 'i' soup("b")[0].renderContents() --> 'foobar'
上の例では示しませんでしたが、renderContentsの結果にタグが含まれない場合には、stringアトリビュートにアクセスすると、内容に直接アクセスできます。
stringを直接書き換えると、renderContentsの結果も書き変わります。
当然、要素を削除することもできます。要素の削除にはextractメソッドを利用します。
a = open("hoge.html") ; a.write("<b>foobar<i>hoge</i></b>"); a.close() soup = BeautifulSoup("hoge.html") tmp = soup("i") tmp.extract() print soup("b")[0] → '<b>foobar</b>'
まだよくわかってませんが、extractメソッドを利用する際には、削除対象となるエレメントのオブジェクトを一度別変数にとっておいてから、extractメソッドを呼びだすようにしないと上手くいかないようでした。
削除とかしたら、当然書き出したりしたくなります。BeautifulSoupはこのへんも簡単にできるようになっていて、上の例でいけばsoupオブジェクトをstrにかけると、保持しているHTML全体を文字列にしますので、これをそのままファイルに書き出せばOKです。
さて、とりあえず自分が使った範囲ではこんなところでしょうか。他にも、動的にエレメントを作ったり追加したり、ということができるようです。
BeautifulSoupは壊れたHTMLでもわりと修復して読みだすことができますので、標準のElementTreeなどの代わりとして十分利用することができます。