Posted at

ブラウザレンダリング後の要素をスクレイピングする

More than 1 year has passed since last update.

自分で作っているプロダクトで、一部他のサイトからスクレイピングをする必要があったものの、JSで動的に生成されている要素だったため、スクレイピングができませんでした。

そのため調べてヘッドレスブラウザを使うことにしたのですが、いろいろあってスクレイピングする必要がなくなり、調べた時間を無駄にしたくないと思いまとめました。。


ヘッドレスブラウザとは

調べてみるとGUIのないブラウザと説明をよく見ます。

ヘッドレス Chrome ことはじめによると下記のような説明がありました。


ヘッドレスブラウザは、GUI を持つ必要のない自動テスト環境やサーバー環境にとてもよいツールです。例としては、実際のウェブページに対してなにかテストを実行する、そのページの PDF を生成する、またはただ、そのページがどう表示されるかを検証するなどが挙げられるでしょうか。


GUIはないけどブラウザが行ってくれている処理をヘッドレスブラウザも行ってくれて、それをプログラムから操作できるという認識で良いのかなと思います。

ヘッドレスブラウザを使うことでブラウザレンダリングが実行され、JSによって生成されるhtmlが取得できるようになります。

今回phantomjsを使用したのですが、すでに開発は終了しているそうなので、触ってみるだけなら良いと思いますが、そうでないなら他に調べて検討をした方が良いと思います。


例としてやろうとしていたスクレイピングについて

細かいライブラリの使い方は公式のPHP PhantomJS - GitHub Pagesを見てもらえればわかるとして、ざっくりと概要だけまとめられればと


取得対象のhtml

jsでpタグのfugaを追加しているのですが、スクレイピングしたかった要素がこのようにjsで動的に生成される要素でした。

<html>

<body>
<div id="text">
<p>hoge</p>
<!-- ここにjsでfugaを追加 -->
</div>
</body>
<script type="text/javascript">
//要素の作成
var element = document.getElementById('text');
var div = document.createElement('p');
div.textContent = 'fuga';

//最後の子要素として追加
element.appendChild(div);
</script>

</html>

下記コマンドでウェブサーバーを起動させ、ブラウザで確認をするとjsが実行されてhoge,fugaと表示がされます。

$ php -S localhost:8080 test.php


phpでスクレイピングをしてみる

そのためfugaをスクレイピングで取得しようとして、JS実行前の値が返ってくるためfugaが取得できません。

(スクレイピングにはGoutteと言うライブラリを使用しています。)

<?php

namespace App\Http\Controllers;

use Goutte\Client;

class ScrapingController extends Controller
{
public function fetchText()
{
$client = new Client();
$crawler = $client->request('GET', 'http://localhost:8080/');

// localhost::8080からdivタグに含まれるテキストを取得
$text = $crawler->filter('div')->text();
var_dump($text); // string(4) "hoge"
}
}

あくまでブラウザで確認している画面はレンダリング後であり、スクレイピングで取得している値はレンダリング前となっているため、hogeしか取得ができないようになっています。


ヘッドレスブラウザを使ってスクレイピングしてみる

先ほどのコードにPhantomJsというヘッドレスブラウザを追加して、ブラウザのレンダリング後のhtmlからスクレイピングをしました。

<?php

namespace App\Http\Controllers;

use Goutte\Client;
use JonnyW\PhantomJs\Client;

class ScrapingController extends Controller
{
public function fetchText()
{
$client = Client::getInstance();
$client->getEngine()->setPath('vendor/bin/phantomjs');

$request = $client->getMessageFactory()->createRequest('http://localhost:8080/', 'GET');
$response = $client->getMessageFactory()->createResponse();

$client->send($request, $response);

$crawler = new Crawler($response->getContent());
$text = $crawler->filter('div')->text();
var_dump($text); // string(20) " hoge fuga"
}
}

jsによってfugaが生成されているため、今回はhoge,fugaの両方が取得できました。


まとめ


  • ヘッドレスブラウザは、GUIは存在しないがブラウザと同じ様な処理を実行してくれる。そしてそれをプログラムから操作できる

  • JSによって動的に生成される要素をスクレイピングするには、ヘッドレスブラウザなどで一度ブラウザレンダリングをさせる

  • phantomjsは開発が終了している