Beautiful Soup 4.x では parser を明示指定しよう
python で スクレイピングなどを行うときに便利なのが BeautifulSoup (ここでは bs4 を扱っています) 。
parserを選択できる仕様になっていますが、 4.3.xまでは明示的に指定しなくても、適度に動いていました (どう動いてたかは、調べてない)。
こちらにあるように、lxmlやhtml5libがインストールされている場合はそちらが優先されるそうです。
4.4.x からは明示的に指定しないと、自動選択されるとともにWARNING がでて、何を使って動いてのかを教えてくれます。
lxml が自動で選ばれた例)
soup = BeautifulSoup(html)
..python2.7/site-packages/bs4/__init__.py:166: UserWarning: No parser was explicitly specified, so I'm using the best available HTML parser for this system ("lxml"). This usually isn't a problem, but if you run this code on another system, or in a different virtual environment, it may use a different parser and behave differently.
ただし、自動選択に依存してしまうと環境によって動作が変わってしまいます。そこで、各parserの特性を理解して、明示的に指定するのが吉ですね。と調べたメモです。
- BautifulSoup 4.4.1 ( by pip. 2016/5 現在の最新版 )
パーサーを選ぶ
HTMLに限定すると次の3つが対応しています。
パーサー | アドバンテージ | ディスアドバンテージ |
---|---|---|
html.parser | Python標準で含まれている | 寛大ではない |
lxml | 高速動作する | 外部のCライブラリ依存 (pip導入時には、libxslt, libxml2などのCライブラリが必要) |
html5lib | 寛大な動作をする(文法間違いの修正度合い)。 Webブラウザと同じ手法でパース。有効なHTML5を作る。 | とても動作が遅い。外部のPythonライブラリ依存がある |
パースしたいページで試したところ、lxml OR html5lib なれば正常に動作していました。lxmlがいいなと思ったのですが、libxslt が古く "/usr/bin/ld: skipping incompatible" (CentOS6) と言われたので、pip で導入できる html5lib を使うことにしました。簡単に動作比較したところlxmlの方が10倍以上早かったので、Cライブラリのハードルがなければ、そっちが良かったかも(あまり厳密なHTML5コーディングも不要だし)。
soup = BeautifulSoup(html, 'html5lib')
※なお html5lib自体は正常にインストールされていれば import する必要ないです。
parser別の特徴の比較。
parser別の動作比較。どれがいいとは言えないが、ポリシーの違いが明確にでる例をあげてくれています。
選択に迷った時は、diagnose() で検証も出来るようになっています。
最終的には、用途やリソース次第ですね。
その他
以前動いてたという理由で、ワーニングとかを無視して進めるのは良くないなぁと気づきました。はい。
今回は、開発を手伝ってもらう際、新しい環境構築を行うことになり気づけました。
急ぎ、README と コード直して、明示的に指定せねば。。。