AWS LambdaでPuppeteerを動かす

## はじめに
AWS LambdaでPuppeteerを動かすためのメモです。
npm の @serverless-chrome/lambda と chrome-remote-interface を使用した例はいくつかありますが、開発停止の影響のためか、一部のPuppeteer APIが動作しなかったので、[chrome-aws-lambda](https://github.com/alixaxel/chrome-aws-lambda) パッケージを使用します。

## 環境
- AWS Lambda
    - ランタイム：Node.js 8.10
- ローカル
    - macOS Mojave(10.14.3)
    - npm 6.8.0

## 手順
### Lambda Layerに登録するパッケージの作成
```
$ mkdir nodejs && cd $_
$ npm i chrome-aws-lambda puppeteer-core
$ cd ..
$ zip -r modules.zip nodejs
```

### Lambda Layer登録
#### AWSのコンソールからLambdaを開く。
#### Layer設定画面を開く
<img width="300" alt="スクリーンショット_2019-02-25_13_41_43.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/fda5f9ce-de47-9c6c-5b8a-f93d96ebec91.png">
#### Layerの作成
<img width="633" alt="スクリーンショット_2019-02-25_13_46_37.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/8777485b-c742-cdce-b0ad-7d00b2291702.png">
#### Layerのアップロード
- 名前: 任意のLayer名
- 説明: 任意の説明文
- コードエントリタイプ: .zipファイルをアップロード
- アップロード: 作成したzipファイルを選択
- 互換性のあるランタイム: Node.js 8.10
- 「作成」をクリック
<img width="739" alt="スクリーンショット 2019-02-25 13.52.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/dca4470e-5784-c672-8d0f-f5d6463956eb.png">

### Lambda関数の作成
#### 関数設定画面を開く
<img width="263" alt="スクリーンショット_2019-02-25_21_09_18.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/06065dbf-dc36-84d1-6dec-cdfa357b0022.png">
#### 関数の作成
<img width="592" alt="スクリーンショット_2019-02-25_21_13_08.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/0b414976-c6b6-749a-dcf4-670a01591868.png">
<img width="653" alt="スクリーンショット 2019-02-25 21.19.02.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/a6f00911-1da8-d920-8e9d-767f2e4e656f.png">

- 名前: 任意の関数名
- ランタイム: Node.js 8.10
- ロール: 1つ以上のテンプレートから新しいロールを作成
- ロール名: 任意のロール名
- ポリシーテンプレート: 未選択で可
- 「関数の作成」をクリック

#### Layerの追加
<img width="583" alt="スクリーンショット_2019-02-25_21_22_48.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/08d905e1-dcd2-6d80-c462-5ba2ad9b5ecc.png">
<img width="1154" alt="スクリーンショット 2019-02-25 21.26.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/7f7f30d6-a2ff-908b-e195-bbdd0980b1b8.png">

- ランタイムと互換性のあるレイヤーのリストから選択
- レイヤー: 登録したLayer名を選択
- バージョン: 登録したLayerの任意のバージョンを選択
- 「追加」をクリック

#### 関数コードを作成
<img width="568" alt="スクリーンショット_2019-02-25_21_41_57.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/8b77ddde-2820-00fc-a836-71cb9a61f67c.png">

``` node.js
const chromium = require('chrome-aws-lambda');
const puppeteer = require('puppeteer-core');

exports.handler = async (event, context) => {
  let result = null;
  let browser = null;

  try {
    browser = await puppeteer.launch({
      args: chromium.args,
      defaultViewport: chromium.defaultViewport,
      executablePath: await chromium.executablePath,
      headless: chromium.headless,
    });

    let page = await browser.newPage();

    await page.goto(event.url || 'https://yahoo.co.jp/');

    result = await page.title();
  } catch (error) {
    return context.fail(error);
  } finally {
    if (browser !== null) {
      await browser.close();
    }
  }

  return context.succeed(result);
};
```

#### 基本設定を調整
<img width="435" alt="スクリーンショット 2019-02-25 21.45.06.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/adf2df16-dd57-3cf9-c7ee-5d504a1718b5.png">

- メモリ: 512MB〜1600MB（chrome-aws-lambdaパッケージ推奨値）
- タイムアウト：任意の時間

#### 保存および実行
<img width="577" alt="スクリーンショット_2019-02-25_21_53_40.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/34aece9f-b878-27e3-eb8d-9cc715a10524.png">
<img width="382" alt="スクリーンショット 2019-02-25 21.57.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/2385a939-bb16-bc9c-986d-1d7a5c731a4d.png">

- イベントテンプレート: Hello World
- イベント名: 任意のイベント名
- 「作成」をクリック

再度、画面右上テストをクリック
#### 実行結果
<img width="567" alt="スクリーンショット_2019-02-25_22_00_44.png" src="https://qiita-image-store.s3.amazonaws.com/0/354791/6b0ee22c-48be-673f-aacb-99178f5c88e9.png">

## まとめ
ブラウザ操作を自動化できるPuppeteerをLambdaで動かせると、API Gateway（API化）やCloudWatch Events（定期バッチ処理）など、他のAWSサービスとの連携が容易になります。
ただでさえ便利なPuppeteerがさらに便利になるので、よければ試してみてください。

## 参考
- https://github.com/alixaxel/chrome-aws-lambda
- https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#running-puppeteer-on-aws-lambda