PHPでスクレイピング
あるサイトのデータを収集したくなったのでHTMLを取得、スクレイピングして情報を抽出することにした。
何を使ってやるか。とは言っても僕に選択肢は少ない。PHPかJava、今だったらnode.js(JavaScript)っていう手もあるかもしれない。
Javaもnodeも現時点で動かすサーバーを持ってない。開発のスピード的に一番慣れているPHPでやるのがよさそうだ。ということでPHPでスクレイピングすることにした。
最初考えていたのがPHPに標準で組み込まれているSimpleXML関数を使ってやる方法。
名前のとおりシンプル、非常に簡単に使えるのでスクレイピングにはもってこいだ。
が、SimpleXMLは”汚いHTML”に弱い。例えば次のようなHTMLがあった時SimpleXMLではエラーになる。
<!-- test.html --> <html> <head> <title>test</title> </head> <body> <div id="hoge">hogehoge </body> </html>
タグが閉じられていないケースだ。これをsimplexml_load_stringで読み込むとエラーになる。厄介なのは<img>タグ等の単独タグで閉じられていない場合にもエラーが出てしまうケースがある事だ。
これではSimpleXMLは使えたものではない。自分が作ったWEBサイトをスクレイピングするならまだしも、一昔前のWEBサイトをスクレイピングするなんて時にはWarningの嵐である。
さてどうするか。何かいいライブラリはないものかなと探してみると、こんなのがあった。
PHP Simple HTML DOM Parser
なんとこのライブラリ、jQueryみたいに簡単に要素を取得していくことができる。
便利。しかもさっきのHTMLなんかも問題なく読み込めてしまう。
<?php require_once('./simple_html_dom.php'); $html = file_get_html('./test.html'); $div = $html->find('div[id=hoge]'); echo $div[0]->plaintext; // 「hogehoge」と出力
これは強い…。
ただfind('div[id=hoge]')ってやったらそのあとは$div->plaintextってやりたいところ。要素が一つの場合でもインデックスを指定してやらないとエラーが出ます。
また注意としてfile_get_htmlで取得したオブジェクトはものすごいでかいです。var_dump()した時に「!?」ってなります。上の数行のHTMLでさえかなり多い。通常のWEBサイトなんかのHTML読み込んだ時にはどんだけ深くなるのか…。ちなみに僕が40kbくらいのHTMLを読み込ませてvar_dumpした時には数秒コンソールに吐き続けてました。
なもんですから実行効率はよくないと思います。検証はしてませんが。でも便利です。
みんなもこれを使ってスクレイピングライフを楽しもう!