LoginSignup
112
111

More than 5 years have passed since last update.

今更ながらPHPでスクレイピングをしてみる

Last updated at Posted at 2016-03-11

以前は、PHP Simple HTML DOM Parserってのを使っていましたが、久しぶりに調べてみると、phpQueryというのがあるようなので、それを使ってみる。

オリジナルのものはここからダウンロードできるようです。
が、しばらくメンテされてないようです。ForkしてComposerに対応したものもあるようです(試してません)。

なお、あまりTableを対象としたサンプルが無かったのでテーブルのスクレイピングを中心に書きます。

シンプルなデモ

このようなHTML(test.html)があるとすると、

<!doctype html>
<html>
<head>
    <title>scraping test</title>
</head>
<body>
<h1>hoge</h1>
<!-- table1 -->
<div id="greeting">Hello</div>
<table>
    <tr>
        <td>name</td>
        <td>hoge</td>
    </tr>
    <tr>
        <td>email</td>
        <td>hoge@hoge.com</td>
    </tr>
</table>

<!-- table2 -->
<table>
    <tr>
        <td>address</td>
        <td>tokyo</td>
    </tr>
    <tr>
        <td>tel</td>
        <td>03-1234-5678</td>
    </tr>
    <tr>
        <td>image</td>
        <td><img src="hoge.png" atl="sample"></td>
    </tr>
    <tr>
        <td>detail</td>
        <td><a href="http://xxx/">more..</a></td>
    </tr>
</table>

<div class="btn">aaa</div>
<div class="btn">bbb</div>

</body>
</html>

例えば、タイトルを取得するのは、 下記のように取れるようである。

<?php

    //require
    require_once('phpQuery-onefile.php');

    //ページ取得
    $html = file_get_contents('./test.html');

    //DOM取得
    $doc = phpQuery::newDocument($html);

    //要素取得
    echo $doc["title"]->text();

なお、要素は、pq()メソッドを使って、

echo pq("title")->text();

と書くこともできるようです。
pq()は、jQueryの$()と等価であると共に、DOMをphpQueryで処理できるよう構造化する機能もあるようです。

基本的な使い方

$doc[""](もしくはpq(""))の""の中身はjQueryのセレクタが使えるので、基本、jQueryと同じように利用すればいいのですが、ちょっとしたクセもあるので、基本的な使い方のメモ。

必要な要素にidが振られていれば、操作に苦労はあまりないのですが、一意なidが振られていない場合は、要素の指定に少々工夫が必要です。

idで指定する

echo $doc["#greeting"]->text();

classで指定する

クラスの場合は複数の要素が存在するので、必要に応じて取得する要素を限定するようにします。

echo $doc[".btn:eq(1)"]->text();

静的に指定する

先述のHTMLには2行2列の2つのテーブルがあります。その2つ目のテーブルの1行目の2列目の要素(tokyo)を取得する場合は、

echo $doc["table:eq(1) tr:eq(0) td:eq(1)"]->text();

のように指定する。find()を利用して、

echo $doc["table:eq(1)"]->find("td:eq(1)")->text();

とも書けるようす。

foreachで回す

複数の値が返ってくる要素は、原則としてforeach()が利用できるようです。
ただ、tableの場合は、各td要素の値を個別に取得することができないようで、あまり使い勝手は良くありません。

foreach($doc["table:eq(0) tr"] as $row)
{
    //各要素取得
    $key   = pq($row)->find("td:eq(0)")->text();
    $value = pq($row)->find("td:eq(1)")->text();

    //表示
    echo $key . " " . $value . "<br>";
}

実務では、後述のcontains等を利用するこの方が多くなります。

利用サンプル

ここでは実開発で利用するサンプルを随時の記述していきます。

特定の行の値を抽出

実運用では、テーブルの場合、特定の要素を抜く需要が多いかとおもいます。
例えばemailという項目を値を取得する場合は、containsと+を利用して、となりの要素を指定したりします。

echo $doc["table"]->find("td:contains('email') + td")->text();

HTMLをそのまま取得

->text()ではなく、->html()を利用すれば、そのままのHTMLが取得できる。

$html = $doc["table:eq(1)"]->find("td:contains('image') + td")->html();

アトリビュートを取得

$src = $doc["table:eq(1)"]->find("td:contains('image') + td img")->attr("src");
$href = $doc["table:eq(1)"]->find("td:contains('detail') + td a")->attr("href");
112
111
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
112
111