[PhantomJS] スクリーンショットを撮ろう!

 今から遡ること数年前、サーバ上でWebページのスクリーンショットを撮りたい、そう思いながら色々と苦戦していた日々がありました。ググれどググれど中々良さげな方法が見当たりませんでした。
 あれから数年、時代は代わりPhantomJSなるheadlessなWebkitベースのツールが出現しました。試しに使ってみたのですがめちゃくちゃ簡単にスクリーンショットが撮れました。というわけで今回はそのへんのメモをば。

PhantomJSとは

 PhantomJSは大雑把に言うと画面のないブラウザです。JavaScriptでさらっとコードを書いてスクリーンショット!みたいなことが出来ます。他にもDOMいじったりいろいろできます。超便利です。

インストールとか

 http://phantomjs.org/からダウンロードしてきてbuild.shを呼ぶだけです。時間は結構かかります。簡単です。ちなみにgccとか必要なモジュールもいくつかありますので先に入れておきましょう。あと日本語フォントも入れておいたほうがよさそうです。以下のサイトがわかりやすいので参考にしてください。

-- CentOS5 系に phantomjs をインストールするのが超簡単だった - Please Sleep

日本語が文字化けする!

 日本語フォントを入れていても文字化けします。フォント周りは色々と設定が必要みたいです。文字化けしちゃった方は以下のサイトを参考にしてみてください。ちなみに以下のサイトではIPAフォントを使っていますが、日本語フォントであれば何でも大丈夫です。

-- FreeBSDとPhantomJSでスクリーンショットを撮る その2
-- phantomjsのrenderで日本語

スクリーンショットを撮る

 というわけで本題のスクリーンショット撮影へ。基本的にはGitHubに上がっているrasterize.jsを使えば可能です。

-- phantomjs/examples/rasterize.js at master · ariya/phantomjs · GitHub

 最小構成なら以下のような感じです。

var page = require('webpage').create();

page.open('http://google.com/', function() {
  window.setTimeout(function() {
    page.render('ss.png');
    phantom.exit();
  }, 200);
});

 ただし、この方法ではロード後に200msしか待機していないので、リソースが大量にあるサイトの場合画像等がロードされない可能性があります。Youtubeなんかだと関連動画のサムネイルが全部グレーになります。コメントも読み込まれません。

 リソースの完全な読み込みを検出することはできなさそうなので、以下のような方法で撮影します。

/*
 * PhantomJS Screen Capture Script
 * Usage: phantomjs capture.js {address} {output}
 */

/* configure */
var width = 1366;
var height = 768;
var zoom = 1.0;
var resourceWaitTime = 3000;

var args = require('system').args;

if(args.length < 3) {
  console.log('few arguments');
  phantom.exit(1);
}

console.log('begin capture: ' + args[1]);

var page = require('webpage').create();
page.zoomFactor = zoom;
page.viewportSize = {
  width: width,
  height: height
};

page.clipRect = {
  left: 0,
  top: 0,
  width: width,
  height: height
}

var timer;

page.onResourceReceived = function(response) {
  timer || clearTimeout(timer);
  timer = setTimeout(capture, resourceWaitTime);
};

function capture() {
  page.render(args[2]);
  console.log('captured: ' + args[1]);
  phantom.exit();
}

page.open(args[1], function () {});

 リソースの受信が完了するとonResourceReceivedが呼び出されるので、その中でタイマーを設定、3秒以上リソースの読み込みがなければページの読み込みが完了したとみなしてスクリーンショットを撮影します。だいたいこれでうまくいくと思いますが回線が細いサイトとかだと途中でスクリーンショットが撮影されてしまうかもしれません。その場合は行頭の「resourceWaitTime」を3000から5000にするとか、もっと長い時間にすればなんとかなると思います。その他のパラメータはスクリーンショットのサイズとか拡大縮小周りの設定です。ただ縮小するとレンダリングが崩れるので、普通に撮影した後にImageMagick等で縮小するのがいいと思います。

まとめ

 PhantomJSを使えばいろいろと面倒だったあれやこれやが簡単高速で実現できちゃいます。マーベラス!!

0 件のコメント :

コメントを投稿