各種スクレイピングのために、レンダリング後(JavaScript実行後)のHTMLを出力するAPIを作る

  • 21
    いいね
  • 0
    コメント

はじめに

スクレイピングをしようとして、いざJavaScriptやPHPやGoogle Apps ScriptでHTMLの取得をすると、JavaScript実行前のソースが取得されてしまう。Seleniumなどを使えばいいが、環境を構築したり起動させっぱなしにしなければいけないので、コストやハードルが高いと感じる。
なのでレンダリング後のHTMLを取得してくれるAPIがあれば様々なプログラムから参照でき、スクレイピングが捗るのではないかと思う。
自分はGoogle Apps Scriptで株価を取得しようとしたところ、参照先がAjaxで株価を動的に生成していたため、スクレイピングできなかっためこのようなAPIが欲しいと思った。
今回は、簡単に実装したかったので、コマンドラインブラウザとしてPhantomJS、API実装としてPHPを使用した。

やりたいこと

  • 簡単にレンダリング後のHTMLを取得できるようにする
  • APIサーバーのメモリ使用量できるだけを抑える
  • GoogleAppsScriptでレンダリング後のHTMLを取得できるようにする

開発環境

  • CentOS 7
  • PhantomJS v2.1 (コマンドラインベースのブラウザ)
  • Httpd 2.4
  • PHP 7.0 (API開発用)

実装の手順

CentOSにHttpdとPHPはインストールされている前提とする

PhantomJSのインストール

Macの場合はbrew installで簡単にインストールできる

$ sudo yum install epel-release 
$ sudo rpm -ivh http://repo.okay.com.mx/centos/6/x86_64/release/okay-release-1-1.noarch.rpm 
$ sudo yum search all phantomjs

PhantomJSでレンダリング後のHTMLを取得する

作業ディレクトリ(/var/www/html/rendered-html/など)に以下のファイルを作成する

下記のソースコードでは、
1. 第二引数で指定したURLの取得
2. ページを取得
3. ページの評価(evalute)を行い、レンダリング後のhtmlタグ内のソースを取得
4. htmlをコマンドラインに出力する
を行なっている。

phantomjs-get-html.js
var page = require('webpage').create();
var system = require('system');
var args = system.args;

var url = args[1];
if (url == undefined) {
    phantom.exit();
}

page.open(url, function(status) {
        if (status === 'success') {
                var body = page.evaluate(function() {
                        return '<html>' + document.getElementsByTagName('html')[0].innerHTML + '</html>';
                });
                console.log(body);
        }
        phantom.exit();
});

上記のソースコードを実行すると、HTMLが取得できる

$ phantomjs phantomjs-get-html.js http://google.com
<html><head><meta content="世界中のあらゆる情報を検索するためのツールを提供しています。さまざまな検索機能を活用して、お探しの情報を見つけてください。" name="descrip...

PHPからPhantomJSを実行する

PHPのPhantomJSを使うという方法もあったが、Composerが多少コストが高いため使用せず
execでPhantomJSを実行し、最終的にJSON形式でHTMLを出力している

index.php
<?php
header('content-type: application/json; charset=utf-8');

//URLの取得 URLがない場合エラー
if(!isset($_GET['url'])){
  statusFailure();
}
$url = $_GET['url'];

//PhantomJSの実行
$cmd = 'phantomjs phantomjs-get-html.js ' . $url;
exec($cmd, $arr);

//データがない場合エラー
if(!$arr){
  statusFailure();
}

//文字列結合
$html = '';
foreach($arr as $val){
  $html .= $val;
}

//JSONにてHTMLを出力
echo json_encode([
  'status' => 'success',
  'html' => $html
]);

//エラー出力関数
function statusFailure(){
  echo json_encode([
    'status' => 'failure',
    'html' => ''
  ]);
  die();
}

実行結果

ブラウザにて、http://IPアドレス/rendered-html/?url=http://google.com にアクセスする
正常に取得できれば、successがかえってきて、HTMLが取得できる

実行結果
{"status":"success","html":"<html><head><meta content=\"\u4e16\u754c...

おわりに

クライアントJavaScriptやGASでもレンダリング後のスクレイピングができるようになったので、やれることが多くなった。今後はクリックやDOM操作もできるAPIに発展させていきたい。