PHPで基本的なウェブスクレイピングをする

今回はPHPで基本的なウェブスクレイピングをする方法を紹介します。

試しに食べログから以下の情報をスクレイピングしてcsvファイルにまとめてみます。

  • タイトル
  • 評価
  • 画像のパス

 

ではやっていきましょう。

1:h3を取得

<?php
  // phpQueryの読み込み
  require_once("./phpQuery-onefile.php");

  // 取得したいwebサイトを読み込む
  $html = file_get_contents("対象のURL");

  // 見出し要素を取得&表示
  echo phpQuery::newDocument($html)->find("h1")->text();
?>

 

phpQueryとはPHPでスクレイピングできるようにするために必要なファイルです。公式サイトからダウンロードできるので「phpQuery-onefile.php」を取り出して好きな場所に配置しましょう。

 

2:csvファイルに書き出す

// ファイルを開く。"a"は書き出し用として開くパラメータ。
$file = fopen("data.csv", "a");

$contents = phpQuery::newDocument($html)->find("h3")->text();

// データを1行書き込む
fwrite($file, $contents."\n");

 

改行するためにエスケープ処理を連結しておきましょう。

 

3:取得した要素を配列に格納してファイルに書き出し

// 取得する要素の数を取得
$title_num = count(phpQuery::newDocument($html)->find("h3")->find(".rvw-item__rst-name"));

// 一つづつ配列に格納
for($i=0;$i<$title_num;$i++){
    $title[] = phpQuery::newDocument($html)->find("h3")->find(".rvw-item__rst-name:eq($i)")->text();
}

// 一つづつファイルに書き出す
foreach($title as $title_element){
    fwrite($file, $title_element."\n");
}

 

for文で要素をどんどん配列に詰め込んでいき、foreachで全部書き出してしまいます。エスケープ処理を忘れずに。

 

4:値段と画像パスを取得し書き込み

for($i=0;$i<$title_num;$i++){
    $title[] = phpQuery::newDocument($html)->find("h3")->find(".rvw-item__rst-name:eq($i)")->text();
    $price[] = phpQuery::newDocument($html)->find(".c-rating__val:eq($i)")->text();
    $image[] = phpQuery::newDocument($html)->find(".rvw-photo__list:eq($i)")->find('img:eq(0)')->attr('src');
    fputs($file, $title[$i].", ".$price[$i].", ".$image[$i]."\n");
}

 

5. リクエスト毎に1〜3秒の時間を空ける

sleep(3);

 

6:ファイルを閉じる

fclose($file);

 

まとめ

ざっくりですがこんな感じです。

最後に全てのコードをまとめておきます。

<?php
  require_once("./phpQuery-onefile.php");
    $file = fopen("data.csv", "w");

    for($p=1;$p<5;$p++){
      $html = file_get_contents("取得したいURL");
        $title_num = count(phpQuery::newDocument($html)->find("h3")->find(".rvw-item__rst-name"));
        for($i=0;$i<$title_num;$i++){
            $title[$p][$i] = phpQuery::newDocument($html)->find("h3")->find(".rvw-item__rst-name:eq($i)")->text();
            $price[$p][$i] = phpQuery::newDocument($html)->find(".c-rating__val:eq($i)")->text();
            fputs($file, $title[$p][$i].", ".$price[$p][$i]."\n");
        }
        sleep(3);
    }

    fclose($file);
?>