PHPのcurl、DOM、XPathでのWebスクレイピング【現役SEが解説】
今回は、PHPのcurl、DOM、XPathでのWebスクレイピングについて、ページ取得とデータ抽出に分け、簡単に解説していきます。
curlでページを取得する方法
PHPでWebスクレイピングを行う場合には、curl関数を使う方法とfile_get_contents関数を使う方法の2種類があります。
しかし、使いやすさや速度の面から前者のcurl関数が使われるケースが多いため、この記事でも、その方法を紹介したいと思います。
$params = array( "keyword" => 'hoge', ); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, "http://hoge.com/hoge"); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_HEADER, TRUE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); curl_setopt($ch, CURLOPT_POST, TRUE); // POSTが必要な場合 curl_setopt($ch, CURLOPT_POSTFIELDS, $params); // POSTパラメータをセット $output = curl_exec($ch) or die('error ' . curl_error($ch)); curl_close($ch);
上記のサンプルは、http://hoge.com/hogeに対し、POSTメソッドでkeywordのパラメータを送信し、Webサーバからレスポンスデータを取得するコードです。
GETメソッドで送信される場合には、POST関連のcurl_setoptを削除して、URLに直接パラメータを埋め込めば、そのままのコードで使うことができると思います。
必要なデータをDOMやXPathで抽出する方法
curlでデータを取得した後は、そのレスポンスデータ、すなわち、HTMLから必要なデータを抽出しなければいけません。
例えば、先程のcurl関数で取得したレスポンスデータが、以下のHTMLのソースコードであった場合を想定してみましょう。
<html> <head> <title>hogeの商品検索結果ページ</title> </head> <body> <div id="content"> <table> <thead> <tr><th>商品名</th><th>価格</th><th>URL</th></tr> </thead> <tbody> <tr><td>商品A</td><td>15,000円</td><td>hoge1.html</td></tr> <tr><td>商品B</td><td>30,000円</td><td>hoge2.html</td></tr> <tr><td>商品C</td><td>45,000円</td><td>hoge3.html</td></tr> </tbody> </table> </div> </body> </html>
ここで、取得したいデータがテーブルの中の商品Aや商品B等の各カラムであるとします。
その場合には、DOMやXPathを使って、以下のようなコードでデータを抽出することができます。
$dom = new DOMDocument(); $html_source = mb_convert_encoding($output, "HTML-ENTITIES", "auto"); @$dom->loadHTML($html_source); $xpath = new DOMXPath($dom); foreach( $xpath->query ( '//div[@id="content"][1]/table[1]/tbody[1]/tr' ) as $node){ $name = $xpath->query('.//td[1]', $node)->item(0)->nodeValue; $price = $xpath->query('.//td[2]', $node)->item(0)->nodeValue; $url = $xpath->query('.//td[3]', $node)->item(0)->nodeValue; echo "{$name}の価格は{$price}でURLは{$url}"; }
細かな解説はここでは割愛しますが、基本的にはHTMLの構造をよく理解したうえでないと抽出することはできません。
例えば、ここではtbodyの中に欲しいレコードが3つ同じ構造であるため、foreach関数でループさせて、それぞれ必要なデータを取得しています。
curlでクッキーを使用する場合
Webスクレイピングの対象のサイトが、ログインを求めてくることもよくあると思います。
そのような場合には、クッキーが必要となりますので、curlでクッキーを設定しなければいけません。
$cookie_path = 'cookie.txt'; // クッキー用ファイルのパス curl_setopt($ch, CURLOPT_COOKIEFILE, $cookie_path); curl_setopt($ch, CURLOPT_COOKIEJAR, $cookie_path);
といっても難しいことではなく、上記のように、クッキー用のファイルを作成し、curl_setoptでその設定を行うだけです。
多少面倒ではありますが、対象のサイトにWebAPIの提供がない場合には、このようにcurlでのWebスクレイピングが最も現実的な手段になります。