【メモ】Webブラウザの操作をJavaScriptで自動化出来る「Puppeteer」のバージョンが1.0になったというニュースが入ったので入門してみた

# Webブラウザの操作をJavaScriptで自動化出来る「Puppeteer」のバージョンが1.0になったというニュースが入ったので入門してみた

インターネットも最も重要なソフトウェアであるブラウザは、いたるところで使われています。しかしながら、人間と対話することを意識された設計であるため、コンピュータで複雑なこと自動操作する前提で作られてはいません。しかしながら、テストやスクレイピングのためにブラウザで動作させた結果を得たい場合があります。

操作を自動化した場合、GUIは不要となる場合が多いです。またGUIは動作が比較的重いため、エンジニアのではGUIの表示をオフにしたいことがしばしばあります。このような機能を実装したブラウザをヘッドレスブラウザ<sup><a href="#sup1">※1</a></sup>（headless browser）とよびます。代表例として、phantomJSがあります。

<sup id="#sup1">※1 [ヘッドレスブラウザのヘッドって何?](https://qiita.com/mabots/items/1f8ba9b54423d91962ee)</sup>

## この記事で使ったスクリプト
- https://github.com/rorono/puppeteer-demo

## Chromeのヘッドレスを体感しよう
- https://developers.google.com/web/updates/2017/04/headless-chrome?hl=ja
- https://chromium.googlesource.com/chromium/src/+/master/headless/README.md
- https://cs.chromium.org/chromium/src/headless/app/headless_shell_switches.cc

```bash
$ chrome \
  --headless \                   # Chrome をヘッドレスモードで実行する
  --disable-gpu \                # 暫定的に必要なフラグ
  --remote-debugging-port=9222 \
  https://www.chromestatus.com   # 開きたい URL（デフォルトは about:blank）
```

※ 現在は、`--disable-gpu` を含めなければいけません。このフラグはそのうち不要にる予定です。


## 「Puppeteer」で出来ること
- サイトのスクリーンショットの生成
- サイトのPDFの作成
- chromeなのでjavascriptが動く
	- JS動作後のWebサイトHTMLのスクレイピング
	- SPA(single page application)にスクロールさせる
	- SSR(server side rendering)を実装する
	- フォームを使ったテストの自動化
- 最新Chromeを使っての最新のJavaScriptやブラウザ機能のテスト
- timeline traceをキャプチャーしてパフォーマンス診断を助ける
- などなど

使い方によってはもっとあると思いますが、思いつくだけでもコレだけあります。
ブラウザを使ってしなければならない処理なら、ほとんどに対応できると考えられます。


## そもそも「Puppeteer」とはなんだろう？

Puppeteerをを事で言うならば、「chromeをnodejsを使って操作することの出来る**ライブラリ**」です。
github公式には、下記のように詳しく描いていますが、「DevToolsプロトコル」とか知らなくても動かせます。

>> Puppeteer is a Node library which provides a high-level API to control headless Chrome or Chromium over the DevTools Protocol. It can also be configured to use full (non-headless) Chrome or Chromium.

> PuppeteerはDevToolsプロトコル<sup><a href="#sup2">※2</a></sup>でヘッドレスChromeまたはChromiumを制御するための高水準APIを提供するNodeライブラリです。フル（ヘッドレスではない）のChromeまたはChromiumを使用するように設定することもできます。

<sup id="#sup2">
※2 DevToolsプロトコル
	- https://chromedevtools.github.io/devtools-protocol/
	- https://developers.google.com/web/updates/2017/04/headless-chrome?hl=ja#frontend
</sup>


## puppeteerが使える環境を整える

今回使用した環境は下記です

- Nodejs version: v8.9.4
- Google Chrome version: 63.0.3239.132（Official Build）（64 ビット）


```bash
$ mkdir puppeteer-demo && cd puppeteer-demo
$ npm init
$ npm install --save puppeteer
```

### `index.js`の作成

```
$ touch index.js
```

### `package.json`に`script`の追加

package.jsonに追加したscriptは実行されると、node_moduleが読み込まれます。

```bash
$ tmpfile=$(mktemp)
$ cat package.json | jq '.scripts.app = "node index.js"' > $tmpfile
$ mv $tmpfile package.json
```

<figure>
  [f:id:careerwave:20180207201352p:plain]
  <figcaption><a href="https://github.com/rorono/puppeteer-demo/commit/34e50652ee1a7bd4fff9b939c40a116e4469769c?diff=unified">Github</a></figcaption>
</figure>


コレで環境は整いました。



## 例１: サイトのスクリーンショットを取得してみる

ここまでできたら、実際に動かしてみましょう。
まずは、サイトのスクリーンショットを取得してみます。

```javascript:index.js
const puppeteer = require('puppeteer');

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

  await browser.close();
})();
```

```
$ npm run app
```

コレで、example.pngが作成されていて、ちゃんとスクリーンショットを取得出来ることがわかります。

[f:id:careerwave:20180207165841p:plain]


## 例２: サイトのスクリーンをPDFで取得する

```javascript:index.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://news.ycombinator.com', {waitUntil: 'networkidle2'});
  await page.pdf({path: 'hn.pdf', format: 'A4'});

  await browser.close();
})();
```

```
$ npm run app
```

[f:id:careerwave:20180207194157p:plain]


## 例３: ブラウザ内でjavascriptを実行する

```javascript:index.js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://example.com');

  // Get the "viewport" of the page, as reported by the page.
  const dimensions = await page.evaluate(() => {
    return {
      width: document.documentElement.clientWidth,
      height: document.documentElement.clientHeight,
      deviceScaleFactor: window.devicePixelRatio
    };
  });

  console.log('Dimensions:', dimensions);

  await browser.close();
})();
```


## 参考リンク
- https://github.com/GoogleChrome/puppeteer
- [Webブラウザの操作をJavaScriptで自動化](https://goo.gl/uEeTxc)