Help us understand the problem. What is going on with this article?

--headless時代の本命? Chrome を Node.jsから操作するライブラリ puppeteer について

More than 1 year has passed since last update.

--headless時代の本命? Chrome を Node.jsから操作するライブラリ puppeteer について

puppeteer はHeadless Chrome をNode.jsで操作しやすくしたライブラリです。今日(※ 2017/8/17)一日で凄い勢いでGitHubのトレンド入りしており、TLでも話題になっていたので、早速触ってみました。

Trending_repositories_on_GitHub_today.png

Node.jsでChromeを操作するというコンテキストにおいては、Nightmare.jsと同じレイヤに属するプロダクトですね。Nightmare.jsはElectronを介在させることで、Chromeの操作を実現していましたが、今年の5月にChromeでheadlessモードが利用可能になって以降1、headless Chromeを直接操作するライブラリが色々と出始めていますね。この系統は、chromyや、やはり先日GitHubでトレンド入りしていたchromelessなどが挙げられます。

puppeteerがこれらのライブラリと一線を画すのは、なんと言っても本家ChromeのDevTool開発チームが作成・メンテナンスしている、という点でしょう。

仕組み

puppeteerは、WebdriverIOのようなクロスブラウザ対応のツールとは異なり、Chrome DevTools Protocol2 を利用してNode.jsからChromeの開発者ツールへ接続して操作を行います。

触ってみる

この手のツールの定番、スクリーンショットの取得をやってみます。

まずはインストール。

npm i puppeteer

postinstallフックにより、chromiumもインストールされます。インストールされるchromiumのバージョンはpuppeteerのpackage.jsonで一意に定まるようになっているため、npmやyarnのロックファイルと併用することで、利用するchromiumのバージョンをコントロール可能です。

続いてブラウザを操作するスクリプトを書いていきます。

script.js
const fs = require('fs');
const assert = require('assert');
const puppeteer = require('puppeteer');

(async() => {

  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://github.com/Quramy');
  await page.screenshot({path: 'example.png'});

  browser.close();
  assert(fs.existsSync('example.png'));
  console.log(' 🎉 ');
})();

特に説明不要ですね。GitHubのプロフィールページを表示してキャプチャを撮るスクリプトです。

下記のコマンドで動作させ、example.pngに画像が出力されていれば成功です。

node script.js

CIでの動作

実際のところ、ローカルでキャプチャを取得しても面白みもへったくれもありません。やはりCIで動かしてこそでしょう。

TravisCI

特に難しい点はありません。通常のNode.jsプロジェクトと同様にymlを書くだけで簡単に動作します。

.travis.yml
os:
- linux
language: node_js
node_js:
- '8'

script:
- node script.js

WebDriverやNightmare.jsの場合は仮想フレームバッファの設定など、ブラウザをCIで動作させるための特殊な設定が必要なのですが、それすらも不要なのは気分がいいですね。

WerckerCI

折角なので、DockerベースのCIでも試してみました。普段から使っているという理由でOracle WerckerCIを選択。
Node.js公式のDocker imageを利用したところ、

(node:227) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): Error: Failed to connect to chrome!
(node:227) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
npm info lifecycle pupperteer-example@1.0.0~posttest: pupperteer-example@1.0.0

というエラーが表示されてしまっため、多少のworkaroundを施しています3。どうやら、Debian系のOSで動作させる場合には、追加でlibxcb関連をインストールした上で、SUID Sandboxを無効化4する必要があるらしいです。

wercker.yml
box: node:8

build:
  steps:
    - script:
        name: Workaround for GoogleChrome/puppeteer#290
        code: sh ./fix_290.sh
    - npm-install
    - npm-test
fix_290.sh
#!/bin/bash

apt-get update
apt-get install -yq gconf-service libasound2 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 \
  libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 \
  libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 \
  libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 \
  ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
script.js(変更部分)
  // argsを明示
  const browser = await puppeteer.launch({ args: ['--no-sandbox', '--disable-setuid-sandbox'] });

とすることで、動作しました。Travisに比べると少しややこしいですね...。
真面目にやるのであれば、上記の依存関係を焼き付けたimageを作ってしまった方が良さそうな気もします5

Werckerだけでなく、CircleCI 2.xのようなDocker baseのCIでpuppeteerを動作させる際は同様の考慮が必要になりそうなので、何かの助けになれば幸いです。

なお、動作検証に利用したレポジトリは https://github.com/Quramy/puppeteer-example です。参考まで。

おわりに

API一覧をざっと眺めてみると、Nightmare.jsで実現できていたことはほぼ全てpuppeteerでも実現できそうな印象です。

スクリプトを送り込むinjectFileや、ブラウザ上でscriptを評価するevaluate、そして、Node.js上で定義した関数をブラウザ上に公開する exposeFunctionあたりを駆使すればほぼ何でも出来るんじゃないかこれは、という予感です。

飽くまでChrome専用の操作には限定されますが、e2eテスト環境であったり、お手軽なDOM環境が欲しいときには重宝しそうです。

僕のチームでは、開発しているWebアプリケーションについては、ブラウザで動作させて画像のキャプチャを取得し、前回との差分を検知することで回帰テストを回しており、これに特化した reg-suit というツールを作成したりしています。
このテストフローについては、別途まとめた記事にしたいと思っていますが、最終的には「如何にCIでキャプチャ画像を取得するか」という点に難しさが収束していく感があり、puppeteerのようなブラウザ操作ツールを上手く活用できる色々と捗りそう。

それでは、また。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした