Puppeteerで定期的にスクリーンショットを取得する方法

たかがスクリーンショット、されどスクリーンショット。

昔からWebページやWebシステムなどのスクリーンショットを手軽に撮りたい、定期的・自動的に撮りたいというニーズは存在し、古くは ImageMagick 利用が主流の時代があり、ここ5年程では Selenium の利用が活発でした。そして2018年現在注目を集めているのが、Google 製の Headless Chrome API の node.js 実装である Puppeteer です。

既に Selenium のノウハウを持っているチームにとっては、Puppeteer の利用自体が大きなパラダイムシフトになるわけではないのかもしれませんが、こういった小さなタスクから最新かつスマートな技術を実験し取り入れていくのが、チーム内のリテラシー向上や学習意欲アップには効果的です。

本記事では、Puppeteer と docker、そして Jenkins を使って、サクッと定期的にスクリーンショットを撮る方法を、実際の現場で利用できるスクリプトと共に紹介します。

シナリオ

以下のような想定で動くものを作ってみましょう。

  • 毎日1回、指定サイトのURLのスクリーンショットを撮る

    • そのサイトには認証が必要である
    • フルサイズのスクリーンショット
  • 撮ったスクリーンショットを Slack に Post

  • できれば Firefox も…

イマドキ!

一昔前であれば、Selenium を動かす Java のコードを書き、それを動かす環境をメンテし続けるという方法が主流でした。2018年現在は docker の隆盛もあり、やはりスクリーンショット取得専用のコンテナを立ち上げて仕事をさせ、すぐに廃棄するというやり方がスマートでしょう。

Let's Try ~まずはマニュアルで~

手順はとっても簡単、docker 利用可能なマシンから以下のコードを叩くだけです。

$ docker run --rm \
    -e SLACK_BOT_TOKEN=xxx-xxx-xxx \
    -e CHANNEL=your-channel \
    -e TARGET_URL=https://example.com/path/to/page \
    -e FULL_PAGE=<span class="hljs-literal">true</span> \
    -e BASIC_AUTH_USERNAME=username \
    -e BASIC_AUTH_PASSWORD=password \
    ryysud/screenshot2slack

注: Slack bot は予め https://my.slack.com/services/new/bot で作成し、ワークスペースに招待しておきましょう

これだけで Slack にスクリーンショットが投稿されます。ファーストビューだけでなくフルページのスクリーンショットを撮るため、 FULL_PAGE=true を同時に設定しています。

Slack 連携が必要なく、ローカルファイルとして取り出したい場合は yamitzky/puppeteer-cli を利用するのもいいかもしれません。こちらのイメージは CJK フォントが予めインストールされているわけではないので、日本語サイトの表示を行うには、外部 CSS, stylesheet の指定による web font の利用が必要です。

Let's Try ~Cookie によるログイン~

ベーシック認証だけでは不十分で、セッションログインが必要な場合は、 cookie の string 表現を環境変数に追加することで対応できます。以下は Redmine にログインできる cookie データを準備する例です。

    COOKIE_VALUE_REDMINE_SESSION='xxxx....'

    # Cookie data for login and multiline opt
    COOKIES_TEMPLATE='
    [
      {
        name: _redmine_session,
        value: %s,
        domain: example.com
      },
      {
        name:
        rb_bl_multiline,
        value: multiline,
        domain: example.com,
        path: /redmine/rb
      }
    ]'
    COOKIES=$(printf $COOKIES_TEMPLATE $COOKIE_VALUE_REDMINE_SESSION | tr '\n' ' ')

    docker run --rm \
      -e SLACK_BOT_TOKEN=xxx-xxx-xxx \
      -e CHANNEL=your-channel \
      -e TARGET_URL=https://example.com/path/to/page \
      -e FULL_PAGE=true \
      -e COOKIES=$COOKIES \
      ryysud/screenshot2slack

Let's Try ~定期実行~

あとは上記を Jenkins で実行するだけです。1 job につき 1 TARGET_URL というルールにしておくとわかりやすいのではないでしょうか。

SLACK_BOT_TOKENCOOKIE_VALUE_REDMINE_SESSION などの秘匿情報は、Credentials で用意して注入するようにしましょう。

おまけ: Firefox 実装

Google 謹製ではありませんが、Puppeteer API の Firefox 実装も公開されています。

autonome/puppeteer-fx

まとめ

スクリーンショットの撮り方には様々な方法がありますが、Puppeteer には Selenium のような煩雑さがなく、puppeteer-fx 利用時も同じ API で同じように node.js 向けのコードを簡単に書くことができる、というところがメリットと言えます。

一方で Puppeteer 自体は飽くまでも Chrome のための Google の実装ですので、Edge やその他のマイナーブラウザを含め、ブラウザ間差異を確認するようなツールとしては向かないかもしれません。

用途に合わせて、今回のコードを利用していただければと思います。