Dockerでpuppeteerを動かしてフォーム予約をする

やりたいこと

結婚式に参列している最中にブラウザから申込フォームの操作をしなければいけなくなったので
crontabを使って指定日時にDockerを立ち上げ、puppeteerを操作して華麗に予約を遂行する

作業ディレクトリの作成

mkdir -p yoyaku/app/script  
cd yoyaku

ディレクトリ構成

yoyaku/
   ├ app/
   |  └ script/
   |       └yoyaku.js
   └ Dockerfile

Dockerfile

FROM node:9.2.0

RUN apt-get update \
 && apt-get install -y \
      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

RUN mkdir -p /puppeteer/app/script
WORKDIR /yoyaku/app
# ローカルからコンテナへ実行ファイルが入ったディレクトリをコピー
COPY app/script /yoyaku/app/script
RUN npm install puppeteer

# スクリーンショットをとるときに文字化けしないようフォントをインストール
RUN mkdir /noto
ADD https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip /noto
WORKDIR /noto
RUN apt-get install -y unzip
RUN unzip NotoSansCJKjp-hinted.zip && \
    mkdir -p /usr/share/fonts/noto && \
    cp *.otf /usr/share/fonts/noto && \
    chmod 644 -R /usr/share/fonts/noto/ && \
    fc-cache -fv
WORKDIR /
RUN rm -rf /noto

#実行するコマンド
ENTRYPOINT ["node","/yoyaku/app/script/yoyaku.js"]

参考にした記事(ありがとうございます) qiita.com morizyun.github.io

yoyaku.js

const puppeteer = require('puppeteer');
const targetUrl = "http://hogehoge.com";

//スリープ用の関数定義
async function sleep(mSec) {
  return new Promise(resolve => setTimeout(resolve, mSec));
}

(async () => {
  const browser = await puppeteer.launch({
    args: [
      '--no-sandbox',
      '--disable-setuid-sandbox'
    ]
  });

  const page = await browser.newPage();
  //ページ移動
  await page.goto(targetUrl);


//以下よく使いそうな処理の例
//-------------------ここから-------------------

  //dialogが出てきたら承認する
  page.on('dialog', async dialog => {
    console.log(dialog.message());
    await dialog.accept();
  });


  //要素のクリック + 遷移がある場合は読み込みを待つ
  page.click('#セレクタ');
  await page.waitForNavigation({timeout: 60000, waitUntil: "domcontentloaded"});

  //文字入力(セレクトボックスの選択などもできる)
  await page.type('input[name="セレクタ"]', '入力したい文字');

  //要素のvalue取得
   var value = await page.$eval('#セレクタ', item =>{
      return item.textContent;
   })

  //ログ出力
  console.log("なんか識別用の文字", 変数名);

  //スリープ(上部で定義した関数呼び出し)
  await sleep(5000);

  //スクリーンショット(実行ディレクトリに保存される)
  await page.screenshot({ path: '画像名' });

  //処理を抜ける
  process.exit();

//-------------------ここまで-------------------

  browser.close();
})();

build

docker build -t yoyaku:latest .
最後の『.』はカレントディレクトリのDockerfileを意味する

run

docker run --rm -it -v `pwd`/app/script:/yoyaku/app/script -w /yoyaku/app/script yoyaku:latest
『-v』でローカルとコンテナ内をマウントする(コンテナ内で保存したスクリーンショットを残すため)
『-w』でワーキングディレクトリを指定する

備考

crontabで設定するときはdocker runコマンドの『-it』をとらないとエラーになる