839の日記

業務とは関係ない趣味の話を書くブログです。

cloud runでpuppeteerを使ってクローラーを作る

もともと借りていたVPS(ubuntu)の上でchromeとchromedriverを入れてクローラを動かしていたが、 何気ないapt-get upgradeで動かなくなってしまい、今後も発生することを考えると憂鬱になったので移行先を探すことに…。

cloud runは感覚的にはdocker imageを投げつけられるlambdaみたいなもので、手元で動くものを作ればimage投げるだけでいけるかな、という算段で選択した。 rest api的にurlにアクセスしたらcrawlした結果を返すようにしたかったため、expressを間に挟んでいる。 常に使いたいわけでもなかったので、使うときだけ起動するcloud runは要件とマッチしていた。

サンプルリポジトリとしては以下で公開している。 github.com

内容としては、GAEでpuppeteerを動かしているサンプルのcloud run版といった感じ。 cloud.google.com

const express = require('express');
const puppeteer = require('puppeteer');
const app = express();

app.use(async (req, res) => {
  const url = req.query.url;

  if (!url) {
    return res.send('Please provide URL as GET parameter, for example: <a href="/?url=https://example.com">?url=https://example.com</a>');
  }

  const browser = await puppeteer.launch({
    args: ['--no-sandbox']
  });
  const page = await browser.newPage();
  await page.goto(url);
  const imageBuffer = await page.screenshot();
  browser.close();

  res.set('Content-Type', 'image/png');
  res.send(imageBuffer);
});

const server = app.listen(process.env.PORT || 8080, err => {
  if (err) return console.error(err);
  const port = server.address().port;
  console.info(`App listening on port ${port}`);
});

ちょっとハマったところはデフォルトはmemory 256MBでデプロイされるが、512MBはないとchromeが起動してくれない点。 上記のgithubのREADMEにも書いているが、 --memory 引数で指定できるので512Mi以上を指定したほうがいい。

f:id:husq:20190514213823p:plain
cloud run log
上記のような感じでログも出るので大体すぐ問題はわかる。

更新はもう一度 gcloud beta run deploy を叩くといい感じにバージョンを切り替えて反映してくれるし、カスタムドメインも利用可能。 ドメインを登録するとCNAMEにこれを指定しろ、と言われるのでそれを指定すればSSLの証明書も勝手にletsencryptで取得して設定してくれる。 lambdaとかでホスティングする場合はapi gatewayの設定をいろいろとしないといけないのでだるいが、cloud runはこの辺がかなりお手軽。

運営しているサイトでchromeを使ってクロールできればかなり効率が上がる刺し身たんぽぽ作業があり、 chrome crawlを使わず手作業でやるのは相当時間的にもしんどかったので、メンテナンスフリーな形で移行できて助かった。

使ってみた感想としてはdocker imageを投げるだけでいい感じに使えるので、statelessなものはガンガン投げていってもいいなと感じた。