Toshusai blog

知識の保管庫

DockerでHeadless Chrome(puppeteer)を使う

DockerでHeadless Chrome(puppeteer)を使う

About

ブラウザ操作にはjsのライブラリpuppeteerを使う GitHub: https://github.com/puppeteer/puppeteer

Docker Image

日本語フォントに対応したHeadless Chrome Dockerコンテナ

FROM mhart/alpine-node:12

ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true

RUN apk update && apk add --no-cache nmap && \\
    echo @edge http://nl.alpinelinux.org/alpine/edge/community >> /etc/apk/repositories && \\
    echo @edge http://nl.alpinelinux.org/alpine/edge/main >> /etc/apk/repositories && \\
    apk update && \\
    apk add --no-cache \\
      chromium \\
      harfbuzz \\
      ttf-freefont \\
      nss

# 日本語フォントをインストールする
RUN mkdir /noto

ADD https://noto-website.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip /noto 

WORKDIR /noto

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

Chromeのバージョンが違うと動かないことがある 上記のDockerfileだと72が入るのでpuppeteerのバージョンを合わせてインストールする。

npm install puppeteer-core@chrome-72

TypeScriptで使うなら

npm install -D @types/pupeteer

executablePathを指定してあげる。Macとかのホストマシンで動かす場合はなくても大丈夫。 --no-sandboxを指定しないとルート権限で動かせない。

const browser = await puppeteer.launch({
    executablePath: \"/usr/bin/chromium-browser\",
    args: ['--no-sandbox'],
    defaultViewport: {
        width: 1920,
        height: 1090
    },
});

APIはここ https://github.com/puppeteer/puppeteer/blob/master/docs/api.md

スクリーンショットを取る

await page = browser.newPage();
page.goto(\"https://example.com\");
await page.screenshot({ path: \"example.png\" });

ボタンを押して遷移を待つ

await Promise.all([
    page.tap(\"button\"),
    page.waitForNavigation({ waitUntil: \"networkidle2\" })
]);

ファイルをアップロードして待つ

const fileInputHandle= await page.$(\"input\");
await fileInputHandle.uploadFile(\"example.png\");
// アップロード後に変化するDOMを指定するとアップロード完了を待てる
await page.waitForSelector(\"#uploaded\");

複数のDOMに対して処理を行う

var texts: Array<string> = await page.$$eval(\"li\", (elements) => elements.map(el => el.innerHTML));

Cookieを再利用する

保存

var cookies = await page.cookies();
writeFileSync(\"cookies.json\", JSON.stringify(cookies));

セット

var cookies: Cookie[] = JSON.parse(readFileSync(\"cookies.json\").toString());
await page.setCookie(...cookies);

参考

https://github.com/mhart/alpine-node https://help.apify.com/en/articles/1640711-how-to-log-in-to-a-website-using-puppeteer https://stackoverflow.com/questions/46948489/puppeteer-wait-page-load-after-form-submit https://qiita.com/go_sagawa/items/85f97deab7ccfdce53ea https://qiita.com/dd511805/items/dfe03c5486bf1421875a https://blog.logrocket.com/how-to-set-up-a-headless-chrome-node-js-server-in-docker/ https://hub.docker.com/r/justinribeiro/chrome-headless/ https://developers.google.com/web/updates/2017/04/headless-chrome