要約:ページから必要な部分だけをXPath式で抽出するPHP製汎用スクレイピングライブラリを作った
いままでスクレイピングを使ったサービス(レシピ検索、書籍在庫一括検索)を作ってきましたが、そこで使ったものを簡単に再利用できるように、PHP5で使える汎用スクレイピングライブラリを作ってみました。
スクレイピング結果の表示はHTMLとXMLとRSS 2.0に対応しています。動作させるにはPEAR::HTTP Clientが必要です。
- 表示サンプル
- PHPをGoogleで検索した結果(HTML)
- PHPをGoogleで検索した結果(XML)
- PHPをGoogleで検索した結果(RSS 2.0)
サンプルではGoogleの検索結果のタイトルと説明を拾って表示する処理をしています。コントローラー部分はこんな感じ。
require_once "HTTP/Client.php";
require_once "scraper.Class.php";
// インスタンスを生成
$scraper = new WebScraper("http://www.google.co.jp/search?q=", "UTF-8");
// キーワードが入力されている場合はゲット
if (!empty($_GET["q"])){
// XMLに変換して格納
$scraper->retrieve();
// 要素を抽出して、変数に代入
$titles = $scraper->pickUpElement('//a[@class="l"]');
$links = $scraper->pickUpElement('//a[@class="l"]/@href');
$descs = $scraper->pickUpElement('//div[@class="std"]');
$count = count($titles);
// キーワードをUTF-8に戻す
$scraper->keyword = $scraper->convertKeyword();
}
switch ($_GET["type"]){
case "html": require("template.html.php"); break;
case "xml" : require("template.xml.php"); break;
case "rss" : require("template.rss.php"); break;
default : require("template.html.php"); break;
}
スクレイピングするURLは動的なもの(検索語などクエリが混ざっているもの)と静的なものに分かれると思います。このライブラリでは、動的なURLの場合にフォームから検索できるようにするため、これらを別々に処理しています。
// インスタンスを生成
$scraper = new WebScraper("http://www.google.co.jp/search?q=", "UTF-8");
今回はGoogleに検索語を投げる処理なので、動的なURLにあたります。もし、静的なURLであれば、インスタンスを生成する際の3番目の引数にtrueを指定してください。
インスタンスを生成する際に、検索語を投げるURL(もしくは静的なURL)とその文字エンコーディングを指定します。
// XMLに変換して格納(その際に不必要なタグを除去)
$scraper->retrieve("<\/?b>");
指定されたURLをゲットしてSimpleXML Objectに変換します。
以下の手順は、バージョンアップにより不要になりました。
その際、タグがネストしているとうまくいかない場合があるので、不必要な要素を消去します。
たとえば、<a href="http://example.com">あれこれ<em>に加えて</em>どれこれ</a>というコードだとa要素の中身を指定しても、あれこれどれこれという風に、em要素の中身がすっ飛んでしまうため、em要素を消しておく必要があります。
よって、ここでHTMLから消去する要素を正規表現で指定しておきます。
// 要素を抽出して、変数に代入
$titles = $scraper->pickUpElement('//a[@class="l"]');
$links = $scraper->pickUpElement('//a[@class="l"]/@href');
$descs = $scraper->pickUpElement('//div[@class="std"]');
$count = count($titles);
さきほど、ゲットしたXMLからゲットしたい部分を抽出して変数に格納します。抽出する部分はXPath式で指定してください。ゲットに成功していれば、文字列が配列で格納されます(CSSはわかるけど、XPathシラネって人はLatest topics > CSS3セレクタとXPathでの表現の対応表 – outsider reflexを参照してみてください)。
格納された文字列は、ビュー部分でたとえば以下のように出力します(例はHTML)
// 設定に失敗していたら離脱
if ($scraper->isError() != false){
$scraper->isError();
} else{
for ($i=0; $i<$count; $i++){
$msg .= "<dt>".$titles[$i]."</dt>";
$msg .= "<dd>".$descs[$i]."</dd>";
}
echo "<dl>". $msg ."</dl>";
}
PHPフレームワーク(rhacoとか)にはスクレイピングライブラリがくっついているし、マイナーだけどSNOOPYというスクレイピングライブラリもありますから、車輪の再発明には違いないんですけどね。perlやrubyみたいにもうちょっとこの手のライブラリが充実していってほしいもんです。
ダウンロード
- ダウンロード
- 汎用スクレイピングライブラリ
- ライセンス
- 修正BSDライセンス
- HTMLParser.Class.php, xhtml1-transitional_dtd.inc.php, XMLフォルダ以下のファイルについてはGNU LGPLライセンス
更新履歴
- v0.2.3 (20080322)
- 検索ワードが変わってしまう問題を解消
- フォームページの記述ミスによりうまく検索できなくなっていた問題を解消
- (ライブラリそのものとはあまり関係ないですが)Google側の仕様変更により、再度検索説明が拾えなくなっていた問題を解消
- v0.2.2 (20080312)
- 要素がうまく拾えない問題を解決しました(Thanks! Phizeさん)
- これに伴い、特定のタグを消去する作業が不要になりました
- v0.2.1 (20080217)
- トップ画面がうまく表示されない問題を修正しました
- 文字エンコーディングの処理を改善しました
- XMLやRSSにおいてパースエラーが発生する可能性がある問題を修正しました
- HTMLを整形式のXML文書に修正するPHPクラスは併用した場合、処理に失敗するケースもあったので、いったん使用しないようにしました
- v0.2 (20080214)
- RSS 2.0での出力を加えました
- HTMLを整形式のXML文書に修正するPHPクラスでの処理を挟みこむようにした
- v0.1
- 初リリース
既知の問題点
- POSTで取得するリソースを取得できない
- 実装自体は簡単ですが、どう実装するかという話です。あんまりオプションを増やしたくないので
- 認証がかかったりソースを取得できない
- これも上記に同じ。このニーズも大きいと思います。
参考にしたURL
Phizeさんがこのスクリプトも含めてPHPのスクレイピングに役立つライブラリをまとめてくださっています。このスクリプトでできないこともありますので、参考にしてください。
- キーワード:





読者のコメント
12件