XPathというのはXPathを扱うための言語構文です。SQLや正規表現のように、PHPをはじめ多くの言語で使うことができる、すばらしく便利な言語です。これを使えば、単にHTML内の特定の文字列を取り出すだけでなく、文字列関数を使った加工まで出来てしまいます。
クローリングするのにわりと使うであろうXPathをいくつか書いてみます。
PHPでXPathを扱うにはPHPコアに含まれるDOMXPathクラスを使う方法、SimpleXMLを使う方法があります。PHPのXPathは1.0の対応です。2.0にはまだ対応していないようです。
HTMLをXMLとして読み込んで使うやり方
いろいろ試してみて、安定した方法が分かってきました。最近はDOMXPathをよく使っています。文字化け対策でutf8のHTMLをHTML-ENTITIESにすると良いようです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
$html = file_get_contents('http://example.jp'); $html = mb_convert_encoding($html, 'HTML-ENTITIES', 'utf-8'); $dom = new DOMDocument(); $dom->preserveWhiteSpace = false; // 連続した空白をまとめる @$dom->loadHTML($html); $domXPath = new DOMXPath($dom); try{ $xpath = '(ここにXPATHを入力)'; $xpath_record = $domXPath->evaluate($xpath); if (is_string($xpath_record)){ $result = $xpath_record; } else { foreach ($xpath_record as $node){ $result = $node->textContent; } } var_dump($result); } catch(Exception $e){ echo '捕捉した例外: ', $e->getMessage(), "\n"; } |
「次へ」もしくは「Next」と書かれたリンクのURLを取得する
1 |
//a[./text()="次へ" or ./text()="Next"]/@href |
2番目以降のliを取り出す
1 |
//ul/li[position()>=2] |
取り出した値を好きなPHPの関数で処理する
最初に名前空間に登録して使います。
1 2 3 |
$xpath = new DOMXPath($dom); $xpath->registerNamespace("php", "http://php.net/xpath"); $xpath->registerPHPFunctions(); //すべての関数を許可する |
1 |
php:function('getPrefecture',//p[@rel="v:addr"]) |
クラスを使う場合は、staticで静的関数にしないと使えません。
1 |
php:function('MyClass::getPrefecture',//p[@rel="v:addr"]) |
のように使えます。
テーブルの行の中でTHヘッダをみて好きな行のTDを取得する
1 |
//table[@class="rst-data"]/tbody/tr/td[preceding-sibling::th="電話番号"] |
リンクURLの中に「*- 」が含まれていた場合は後半のみ取得、含まれていない場合はそのまま取得する
1 2 |
concat(substring-after(//div[@class="rstname-wrap"]/strong/a[contains(@href,'*-')]/@href,"*-"),//div[@class="rstname- wrap"]/strong/a[not(contains(@href,'*-'))]/@href) |
他のサンプル
AutoPagerize WikiのXPath Cookbook
MicrosoftDeveloperNetwork XPathの例
wikipediaのXPathのページ(サンプルではないけど分かりやすいので最初に読むといい)