PhantomJS + Node.js + Docker + Arukas で Web ページのスクリーンショットを撮る
PhantomJS + Node.js + Docker + Arukas を使って、Web ページのスクリーンショットを撮る Web サービスを作ってみる。
サービス仕様
HTTP でリクエストを待ち受け、ユーザからリクエストが来ると、指定された URL のスクリーンショットを撮影し、ユーザに返答する。
環境
開発環境
Mac OS 10.11
本番環境
Ubuntu 16.04 Server on Docker on Arukas
使用するもの
PhantomJS
ヘッドレスなウェブブラウザ。スクリーンショットを撮るのに使用する。
Node.js
サーバサイドで動く JavaScript 環境。Web サーバを上げるのに使用する。
http://nodejs.jp/nodejs.org_ja/
Docker
軽量な仮想環境。今回作るアプリケーションは Docker のコンテナにする。
Arukas
Docker コンテナのホスティングサービス。さくらインターネットが提供しており、現在はβ期間中につき無償である。
実装
スクリーンショットの撮影
まず PhantomJS をインストールする。Mac なら brew でインストールできる。
$ brew install phantomjs $ phantomjs -v 2.1.1
PhantomJS の Quick Start を参考に、次のサンプルコードを作成する。ファイル名は yahoo.js
とする。
var page = require('webpage').create(); page.viewportSize = { width: 800, height: 600 }; page.clipRect = { top: 0, left: 0, width: 800, height: 600 }; page.open('http://www.yahoo.co.jp/', function (status) { console.log('Status: ' + status); if (status === 'success') { page.render('yahoo.png'); } phantom.exit(); });
作った js ファイルを実行する。
$ phantomjs yahoo.js Status: success
すると、次のようにページのスクリーンショットが撮れる。
Web サーバの起動
Node.js と Web フレームワークの Express を使って Web サーバを上げる。
まず Node.js をインストールするために、同じく brew で nodebrew をインストールする。
$ brew install nodebrew $ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.bashrc $ . ~/.bashrc $ mkdir -p ~/.nodebrew/src
nodebrew で最新版の Node.js をインストールする。
$ nodebrew install-binary stable $ nodebrew ls v7.6.0 current: none $ nodebrew use v7.6.0 $ node -v v7.6.0
次に npm コマンドでプロジェクトを作成して、Express パッケージをインストールする。
$ mkdir myapp $ cd myapp $ npm init (enter 連打) $ npm install express --save
Express の「Hello World」の例 を参考にして、Express で Web サーバを起動するプログラム app.js
を作成する。
var express = require('express'); var app = express(); app.get('/', function (req, res) { res.send('Hello World!'); }); app.listen(3000, function () { console.log('Example app listening on port 3000!'); });
作ったプログラムを実行する。
$ node app.js Example app listening on port 3000!
3000番ポートで Web サーバが上がるので、別のターミナルでアクセスしてみる。
$ curl -i http://localhost:3000/ HTTP/1.1 200 OK X-Powered-By: Express Content-Type: text/html; charset=utf-8 Content-Length: 12 ETag: W/"c-7Qdih1MuhjZehB6Sv8UNjA" Date: Sat, 25 Feb 2017 07:51:16 GMT Connection: keep-alive Hello World!
アクセスできた。
webshot の利用
PhantomJS のラッパ webshot を使ってスクリーンショットを撮る。画像は Base64 エンコードして返すようにする。
先ほどと同様に npm で webshot をインストールする。
$ npm install webshot --save
app.js
を次のように書き換える。Node.js は非同期で実行されるので、res.end();
を送るタイミングがポイントとなる。
var express = require('express'); var webshot = require('webshot'); var app = express(); app.get('/', function (req, res) { var options = { screenSize: { width: 800, height: 600 } }; var rs = webshot(req.query.url, options); rs.on('data', function (data) { res.write(data.toString('base64')); }); rs.on('end', function () { res.end(); }); }); app.listen(3000, function () { console.log('Example app listening on port 3000!'); });
同じく app.js
を実行する。
$ node app.js Example app listening on port 3000!
アクセスしてみる。
$ curl 'http://localhost:3000/?url=http://www.goo.ne.jp/' \ | base64 -D > goo.png
指定した URL のスクリーンショットが撮れている。
Docker コンテナ化
Node.js アプリケーションを Docker のコンテナ上で動かす。Docker はあらかじめダウンロードしてインストールしておく。
今回は「できあがったものがこちらです」的に、Hiroshi K. さんが作成したより高機能なアプリを使うこととする。Node.js の起動には supervisord が使われている。
Docker イメージの作成には Dockerfile を使用する。今回の場合、おおまかに次のような流れになる。
FROM
でベースとなるコンテナを作成するRUN
で必要な apt パッケージと Node.js、PhantomJS をインストールするRUN
で GitHub からアプリを clone し、必要な npm パッケージをインストールするEXPOSE
でポートをコンテナの外部に開くENTRYPOINT
で supervisord を起動する
完成した Dockerfile は gist に置いておいた。
この Dockerfile を使ってコンテナをビルドしてイメージ化する。
$ wget -O Dockerfile https://gist.githubusercontent.com/akagisho/466374d7dda0d9bf55321b3b554e91f9/raw/Dockerfile $ docker build -t akagisho/snapshot .
ビルドした Docker イメージからコンテナを起動する。
$ docker run -d -p 3000:3000 akagisho/snapshot
localhost の3000番ポートにアクセスすると、Base64 デコードされたスクリーンショットが返ってくる。
$ curl -XPOST --data 'target=http://www.google.com/' http://localhost:3000/ \ | base64 -D > google.png
Arukas にデプロイ
さくらインターネットが提供する Docker コンテナホスティングサービスの Arukas に、作成したコンテナをデプロイしてみる。
Arukas は現在はβ期間中につき無償とのこと。アカウント発行まで2週間くらいかかるので、登録は事前にやっておく。
Arukas でコンテナを使うには、あらかじめコンテナを Docker Hub に登録しておく必要があるので、Docker Hub のアカウントもあらかじめ登録しておく。
Docker Hub のアカウントを登録したら、ログインする。
$ docker login
先に作成した Docker イメージを Docker Hub に push する。
$ docker push akagisho/snapshot
Docker Hub に push したイメージを Arukas に登録する。
登録したアプリケーションを起動する。
初回はデプロイに10分弱くらいかかる。デプロイが完了するとアプリケーションが起動する。
起動したアプリの Endpoint の URL にアクセスしてみる。
$ curl -XPOST --data "target=http://www.ugtop.com/spill.shtml" \ https://sleepy-euler-3682.arukascloud.io/ \ | base64 -D > screenshot.png
スクリーンショットが保存されれば成功だ。
なおこのアプリケーションは認証等がなく、URL さえわかれば誰でも使用できてしまうので、必要ないときは停止しておく。
P.S.
既に同じようなことをやってる人がいた。