はじめに
Chrome/Chromiumは最近ヘッドレスに対応しています。ヘッドレスは簡単に言えば画面を表示せずブラウザのエンジン部分だけを実行するようなモードで、GUIを有効にしていないVMでもコマンドラインや他のプログラムから起動・操作でき、自動テストや画面キャプチャなどに便利なツールです。今までは私はPhamtomJSを使ってきたのですが、今後の潮流はこちらに移るようですので試しにheadless chrome/chromiumの動作を確認しながらサンプルアプリを作ってみました。
作るサンプルアプリの仕様
http://ホスト名:8888/?width=1000&height=600&&url=http%3A%2F%2Fwww.yahoo.co.jp%2F
こんな感じで呼ぶと、指定されたページのスクリーンショットをPNGで返してくれるアプリを作ることにします。ブラウザでこのURLを叩くとPNGが表示されるイメージです。ページはURLのQuery Stringで与え、w, hのパラメータが返す画像のサイズ(それぞれ幅・高さ、単位はpixel)、スクリーンショットを撮りたいページのURLはURLエンコードした上で、urlパラメータに渡します。
サンプルアプリですので、セキュリティ、パフォーマンス、同時接続性などは考慮されていません。あくまで原理確認用のサンプルアプリです。
材料
Node.js上で動くPuppeteerを使ってヘッドレスモードのChromeを制御します。また今回はRESTのリクエストに答えて動作させるため、同じくNode.js上のフレームワークのexpressを使います。
UbuntuのVMを準備
今回はAWSのこのマシンイメージを使いました。
"Ubuntu Server 16.04 LTS (HVM), SSD Volume Type - ami-bec974d8"
Chromeのインストール
あらかじめGoogleのChromeのサイトの「Chrome for Linux をダウンロード」のぺージから、64bit版のdebianパッケージをダウンロードしておきます(この記事書いている時はgoogle-chrome-stable_current_amd64.deb
というファイル名でダウンロードできています)。そして出来立てホヤホヤのUbuntuのVMにsshでログインし以下を実行します。
sudo apt-get update
sudo apt-get install libappindicator1 gconf-service libasound2 libgconf-2-4 libnspr4 libxss1 fonts-liberation libnss3 xdg-utils
sudo dpkg -i google-chrome-stable_current_amd64.deb
エラーが出たらエラーメッセージを頑張って見ましょう。多分依存ライブラリが足りません。頑張ってそれを含むパッケージを見つけて追加インストールしてから再度チャレンジします。再度チャレンジする場合は、一旦sudo apt-get remove google-chrome-stable
を実行して、半端にインストールされたchromeを取り除いてから再度dpkg -i
を実行するのが良いようです(参考)。
無事インストールできたら以下のコマンドで起動できます。
/opt/google/chrome/chrome --user-data-dir="./user-data-dir" --headless --disable-gpu --remote-debugging-port=9222 https://www.google.com
動作確認(しなくてもいいけど)
上記の起動の例では、Remote debugging port 9222で起動していますので、ローカルマシンからhttp://localhost:9222
でブラウザを使って接続すれば、GUIで動作確認できますが、そもそもAWS上のインスタンスでheadlessのブラウザ立てようとしている訳なのでVNCとかセットアップしたくないですよね。ポートむやみに開けたくないかもしれないし。ということでsshのポートフォワードでアクセスしてみます。
一回sshを抜けて、以下で入り直します。
ssh -i ~/.ssh/mykey.pem -L 9999:localhost:9222 ubuntu@54.xx.yy.zz
または、~/.ssh/config
に以下のエントリを書いておいて、ssh headless
でログインします。
Host headless
HostName 54.xx.yy.zz
Port 22
User ubuntu
GatewayPorts yes
LocalForward 9999 localhost:9222
IdentityFile ~/.ssh/mykey.pem
「54.xx.yy.zz」「/.ssh/mykey.pem」にはご自身のホストのIPアドレスやkey fileへのパスに書き換えてください。
この設定でsshにログインしたままブラウザで、http://localhost:9999
にアクセスするとリモートのUbuntuの9222に転送され、「Inspectable WebContents」(すなわちデバッグ可能な画面一覧)の画面が表示されます。その下に開いている画面(タブ)の数だけリンクがあると思いますので、そのリンクを押すと、headlessのchromeでアクセスしている画面とそのDeveloper Tools画面が表示されます。
日本語フォントのインストール
多分、日本語フォントが正しく表示されず、四角(いわゆる豆腐)が表示されていますよね?
AWSのUbuntuイメージは最初から日本語フォントが入っていないようなので、以下でインストールします。
sudo apt-get update
sudo apt-get install fonts-ipafont-gothic fonts-ipafont-mincho
node.jsとnpmのインストール
ここは、こちらの手順をそのまま実行させていただきました!
sudo apt-get update
sudo apt-get install nodejs npm
sudo npm cache clean
sudo npm install n -g
sudo n stable
sudo ln -sf /usr/local/bin/node /usr/bin/node
sudo apt-get purge -y nodejs npm
インストールできたかはnode -v
で確認できます。
yarnのインストール
公式サイトの手順そのままです!
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -
echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list
sudo apt-get update
sudo apt-get install yarn
expressのインストール
yarn add express
puppetterのインストール
yarn add puppeteer
サンプルプログラムの実装
以下を適当なファイル名(例えば sample.js)でセーブしてください。
const puppeteer = require('puppeteer');
const express = require('express');
const fs = require('fs');
const PORT = 8888;
const DEFAULT_WIDTH = 800;
const DEFAULT_HEIGHT = 600;
const DEFAULT_URL = 'http://www.google.com/'
var app = express();
app.get('/', function(req, res){
(async() => {
// クエリパラメータから、w, h, URLを取得(なければデフォルトを使う)
var w = parseInt(req.query.width ? req.query.width : DEFAULT_WIDTH, 10);
var h = parseInt(req.query.height ? req.query.height : DEFAULT_HEIGHT, 10);
var url = req.query.url ? decodeURIComponent(req.query.url) : DEFAULT_URL;
// ブラウザを起動し、新規ページを生成
const browser = await puppeteer.launch();
const page = await browser.newPage();
// ページサイズをセットし、指定されたURLをロード
await page.setViewport({width: w, height: h, isMobile: true});
await page.goto(url, {waitUntil: 'networkidle0'});
// カレントディレクトリにpage.pngでスクリーンショットをセーブし、ブラウザを終了させる
await page.screenshot({path: 'page.png', fullPage: false});
browser.close();
console.log("browser closed");
// カレントディレクトリにセーブしたpage.pngをバイナリで返却する
var img = fs.readFileSync('./page.png');
res.writeHead(200, {'Content-Type': 'image/png' });
res.end(img, 'binary');
})();
});
app.listen(PORT);
console.log(`Server running at http://localhost:${PORT}/`);
実行
node sample.js
で実行します。
あとは、手元のブラウザから、
http://ホスト名:8888/?width=1200&height=400&url=http%3A%2F%2Fwww.yahoo.co.jp%2F
などと叩いて見てください。ポート番号を空けておく(AWSだとSecurity GroupでTCP/8888のinboundを許可しておく)のを忘れずに。
おまけ:もう一つのChrome(Chromium)のインストール方法
こちらを参考にした方法です。
まず依存ライブラリをインストールします。unzipは下記のインストーラ(update.sh)内で必要です。
sudo apt-get install unzip libgtk-3-0 libnss3-dev libxss1 libgconf-2-4 libasound2
次に、latestのchromiumのダウンロードとインストールです。
git clone https://github.com/scheib/chromium-latest-linux
cd chromium-latest-linux
./update.sh
起動は以下のコマンドで。
./latest/chrome --user-data-dir="~/user-data-dir" --headless --disable-gpu --remote-debugging-port=9222 https://www.yahoo.com