Liner Note

情報(ユーザー中心デザイン・ユーザビリティ)と技術(ウェブプログラミング・ウェブサービス)についてのメモ書き

要約:ページから必要な部分だけをXPath式で抽出するPHP製汎用スクレイピングライブラリを作った

いままでスクレイピングを使ったサービス(レシピ検索書籍在庫一括検索)を作ってきましたが、そこで使ったものを簡単に再利用できるように、PHP5で使える汎用スクレイピングライブラリを作ってみました。

スクレイピング結果の表示はHTMLとXMLとRSS 2.0に対応しています。動作させるにはPEAR::HTTP Clientが必要です。

表示サンプル
PHPをGoogleで検索した結果(HTML)
PHPをGoogleで検索した結果(XML)
PHPをGoogleで検索した結果(RSS 2.0)

サンプルではGoogleの検索結果のタイトルと説明を拾って表示する処理をしています。コントローラー部分はこんな感じ。

PHPソースコード
<?php
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)

PHPソースコード
<?php
  
  // 設定に失敗していたら離脱
  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のスクレイピングに役立つライブラリをまとめてくださっています。このスクリプトでできないこともありますので、参考にしてください。

キーワード:

似たもの記事

読者の皆さんの反応サイト内コメントの更新情報(RSSフィード)

読者のコメント

12

ブックマークコメント

4

他サイトの関連記事

1

読者のコメント

  1. お名前

    surge

    投稿日時
    2008年02月12日
    1時ごろ
    Comment No
    #1

    是非PEARに登録を♪すげぇっす

  2. お名前

    Phize

    投稿日時
    2008年03月10日
    12時ごろ
    Comment No
    #3

    こんにちは。シンプルなスクレイピングライブラリということで、今、こちらのライブラリを試させていただいてます。

    >// XMLに変換して格納(その際に不必要なタグを除去)
    >$scraper->retrieve(““);

    の部分なのですが、pickUpElementメソッドを

    foreach ($xml->xpath($xpath) as $item){
    $items[] = (string) str_replace(‘&’, ‘&’, $item->asXML());
    }

    のようにすると、入れ子になった要素がすっ飛ばなくなり、retrieveメソッドでのタグ除去が不要になりました。

    他の問題がないかどうかはまだ試し中なのでわかりませんが…。

  3. お名前

    Phize

    投稿日時
    2008年03月10日
    12時ごろ
    Comment No
    #4

    すみません、アンパサンドが変換されてしまったので改めて…。

    foreach ($xml->xpath($xpath) as $item){
    $items[] = (string) str_replace(‘&amp;’, ‘&’, $item->asXML());
    }

    念のため…「str_replace(‘&amp;’, ‘&’, $item->asXML())」です。

  4. お名前

    shin

    投稿日時
    2008年03月13日
    11時ごろ
    Comment No
    #6

    Googleの構造かわってないですか?
    fontがなくなってるみたいです。

  5. お名前

    名無しさん

    投稿日時
    2008年08月08日
    11時ごろ
    Comment No
    #8

    はじめまして、ちょうどRSS変換を行ってみたいと思い、
    調べてたどり着きました。

    早速試させていただいているのですが、特殊文字「>>(raquo;)」や
    「・(·)」が文字化けしてしまいます。。

    HTML出力は問題ないですが、RSSとXMLは共に化けてしまいます。

    「http://tech.openvista.jp/scraping/」
     ↑こちらでは正しく動作しているようです。

    サンプルダウンロード後、変更せずにテスト環境へアップして
    試しております。

    ご教授いただければ幸いです。    

  6. お名前

    名無しさん

    投稿日時
    2008年08月08日
    14時ごろ
    Comment No
    #10

    問題なく検索できるようになりました!

    迅速なご対応、大変感謝しております。

  7. お名前

    名無しさん

    投稿日時
    2008年12月29日
    13時ごろ
    Comment No
    #11

    検索キーワード にキーワードを入力し、「~ゲット」をすると真っ白な画面が出力されます。
    error_reporting(2047)にしたところ..
    下記が表示されます。 判りますでしょうか??

    Notice: Undefined property: url in /****************/httpdocs/scraping/scraper.Class.php on line 91

    Notice: Undefined property: encoding in /****************/httpdocs/scraping/scraper.Class.php on line 94

    Notice: Undefined property: encoding in /****************/httpdocs/scraping/scraper.Class.php on line 97

    Notice: Undefined property: encoding in /****************/httpdocs/scraping/scraper.Class.php on line 102

    Warning: mb_convert_encoding() [function.mb-convert-encoding]: Illegal character encoding specified in /****************/httpdocs/scraping/scraper.Class.php on line 102

  8. お名前

    名無しさん

    投稿日時
    2008年12月29日
    15時ごろ
    Comment No
    #12

    (@◇@;) ウ・・・ PHP4では無理でしたか!?
    まいったなぁー。
    使いたいのに..

はてなブックマークでつけられたコメント

smilestyle55さんのプロフィール画像  smilestyle55
スクレイピング
mitainaさんのプロフィール画像  mitaina
PHP
carneliansさんのプロフィール画像  carnelians
スクレイピング(PHP)
michael-unltdさんのプロフィール画像  michael-unltd
google search scraping for PHP

他サイトの関連記事

  1. ウェブサイト

    ぱふぅ家のホームページ

    投稿日時
    2009年06月07日
    11時ごろ
    Comment No
    #1

    PHPで駅の近くの珈琲店を探す

    PHPで駅データ.jpを利用し、駅の近くの珈琲店を探す。DOM XML(PHP4)、SimpleXML(PHP5)、PHP XML Library(Keith Devens.com)によるプログラムを示す。


トラックバックとは
この記事に言及したサイトをこちらに掲載する仕組みをトラックバックと言います。ここでは、このサイトに頂いたトラックバックを一覧表示しています。
トラックバックしてくださる方へ
この記事への言及がない記事など、トラックバック受信方針に沿っていないものは、読者にお見せしても仕方ないこともあり削除させていただいることをご了承ください。
トラックバックを受け取るためのURI

コメント書き込みフォーム

  • メールアドレスはウェブ上で公開したり、連絡以外で使うことはありません
  • コメントを公開したくないが、作者に連絡を取りたい場合は メールで連絡してください
  • 本文中にHTMLコードは使用できません(URLはそのままお書きください)