PHPでスクレイピング

あるサイトのデータを収集したくなったのでHTMLを取得、スクレイピングして情報を抽出することにした。
何を使ってやるか。とは言っても僕に選択肢は少ない。PHPJava、今だったら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した時には数秒コンソールに吐き続けてました。
なもんですから実行効率はよくないと思います。検証はしてませんが。でも便利です。

みんなもこれを使ってスクレイピングライフを楽しもう!