はじめに
この記事は PHP Advent Calendar 2017 - Qiita の22日目の記事です。
昨日の記事は Khigashiguchi さんの PHPでTDD開発するまでに通った道のり - Qiita でした。
PHP で Web ページのスクレイピングをする
ページのスクレイピングといえば、RubyでNokogiriを使ってやったりというイメージがあるのですが、いろんな言語でスクレイピングできるようになっておいたほうがいいかなtお思い、今回はPHPでサクッと出来ないか試してみました。
利用するのはGuzzleHttpとDOMDocument
DOMDocument
DOMDocumentはPHPの標準ライブラリてきなやつです。
http://php.net/manual/ja/class.domdocument.php
HTML(XML)を解析してくれます。標準ライブラリなので特別にインストールをする必要はありません。
DOMXpath
XPathを書くとDOMDocumentの中からDOMを探してきてくれます。
http://php.net/manual/ja/class.domxpath.php
これもPHP標準で入っているのでインストール等の必要はありません。
GuzzleHttp
GuzzleHttpは、PHPだと一番メジャーかなと思われるHTTPリクエストを行うためのライブラリです。
GuzzleHttpのインストール
composerを使ってインストールします。composerの使い方に関しては省略します。
$ cat composer.json { "name": "yoshikyoto/php-jra", "authors": [], "autoload": { "psr-4": { "Jra\\" : "src" } }, "require": { "guzzlehttp/guzzle": "6.0" } } $ composer install
スクレイピングしてみる
今回は、JRAのトップページの「今週の開催競馬場・注目レース」に表示されているレースのURL一覧を取得してくることにします。
GuzzleHttpを使ってHTTPリクエストを送る
GuzzleHttpを使って、簡単なHTTPリクエストを送ってみます。
<?php require_once __DIR__ . '/vendor/autoload.php'; $client = new \GuzzleHttp\Client([ 'base_uri' => 'http://www.jra.go.jp', ]); $response = $client->get('/'); var_dump($response->getBody()->getContents());
とても分かりやすいです。JRAのページにリクエストを送ってみて、結果のHTMLをvar_dumpするコードです。
Guzzleで受け取った結果をDOMDocumentに渡して解析する
ではGuzzleで受け取ったHTMLをDOMDocumentに渡して目的の情報を取得してみようかと思います。
$client = new \GuzzleHttp\Client([ 'base_uri' => 'http://www.jra.go.jp', ]); $response = $client->get('/'); $document = new \DOMDocument(); @$document->loadHTML($response->getBody()->getContents());
GuzzleHttpで取得してきたHTML列を、そのままDOMDocumentのloadHTMLにかませます。ここで注意が必要なのが、 loadHTML
の行にある @
です。 @
はPHPの文法で、「その行で発生するエラーメッセージを抑制する」というものです。Webをスクレイピングしていると、開始タグに対して終了タグが無いHTMLなど、不正なHTMLが大量にあります。Webブラウザはこれをいい感じに解釈して表示してくれるので問題ありませんが、XMLとしては不正なため、大量のWarningが出てしまいます。そこで、@
を付けることでWarningが出るのを抑制します。Warningは出ますがDOMの解析は大抵正しくできています。
DOMXPath を使ってDOMを取得する
DOMXPath を使って、注目レースのaタグを取得してきます。
$document = new \DOMDocument(); @$document->loadHTML($response->getBody()->getContents()); $xpath = new \DOMXPath($document); $nodes = $xpath->query('//div[@class="race"]//a'); var_dump($nodes);
実行結果
$ php test.php object(DOMNodeList)#31 (1) { ["length"]=> int(3) }
XPathの書き方は PHPネイティブのDOMによるスクレイピング入門 - Qiita のあたりが参考になります。
//div[@class="race"]//a
はページにあるdivのうち、class="race"
なものを取ってきて、その中にあるaタグを取得してきます。
DOMの中の属性などを取得する
最後にaタグの中身とhref属性を取ってこようかと思います。
$nodes = $xpath->query('//div[@class="race"]//a'); foreach($nodes as $node) { echo $node->nodeValue . "\t" . $node->getAttribute('href') . PHP_EOL; }
nodeValue
はそのDOMで囲まれた中身の値を取得できます。
getAttribute
はそのDOMに指定された属性の値を取得できます。
実行結果
$ php test.php 中山大障害 /keiba/thisweek/2017/1223_1/ 有馬記念 /keiba/thisweek/2017/1224_1/ 阪神カップ /keiba/thisweek/2017/1223_2/
まとめ
以上の知識があればHTMlのスクレイピングが可能となります。
今回はリクエストの部分を使いやすくするために、GuzzleHttpというライブラリを利用しましたが、file_put_contents
等を使えばライブラリを導入することなくスクレイピングすることもできます。
ぜひ皆さんもPHPでスクレイピングしてみましょう。