PHPのcurl、DOM、XPathでのWebスクレイピング【現役SEが解説】

PROGRAM

今回は、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スクレイピングが最も現実的な手段になります。