Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

AWS Lambda上でpuppeteerを動かして、スクレイピングする

More than 1 year has passed since last update.

はじめに

AWS Lambda上のヘッドレスブラウザで動かしたいものがあったので、それの備忘録も兼ねて書いておきます。ちなみに所属会社で似たようなことをしているのですが、PhatomJS(オワコンなのは知ってる)をAWS Lambda上で動かすために、わざわざカスタマイズしてからそれ専用にビルドするという変態技が使われている部分を書き換えたいという想いからの実験でもあります。

そこで本記事ではpuppeteer(パペティア?読み方あってる?)を使って、AWS Lambda上でヘッドレスブラウザを動かすということをしてみます。

サンプルとは少し異なりますが、実際にやってみたソースはこちらです。
https://github.com/chimame/search_ranking_checker_on_aws_lambda

前提条件

本記事は以下のライブラリ等を使用しております。
Nodejs: 8.10
puppeteer: 1.10.0

AWS Lambda上でのヘッドレスブラウザ

みんな大好きサーバーレスのAWS Lambdaでヘッドレスブラウザを動かしてごにょごにょします。

プログラム

とりあえず四の五の言わずプログラムを貼る

index.js
const launchChrome = require('@serverless-chrome/lambda')
const CDP = require('chrome-remote-interface')
const puppeteer = require('puppeteer')

exports.handler = async (event, context, callback) => {
  try {
    // chromeを起動して、puppeteerから操作できるようにする
    const slsChrome = await launchChrome()
    const browser = await puppeteer.connect({ 
      browserWSEndpoint: (await CDP.Version()).webSocketDebuggerUrl 
    })
    const context = browser.defaultBrowserContext()
    const page = await context.newPage()

    // ブラウザ操作(Googleでの検索結果)
    await page.goto(`https://www.google.co.jp/search?q=${event.searchWord}`, { waitUntil: 'domcontentloaded' })

    const searchResults = await page.evaluate(() => {
      const ret = []
      const nodeList = document.querySelectorAll("div#search h3")

      nodeList.forEach(node => {
        ret.push(node.innerText)
      })

      return ret
    })

    return callback(null, JSON.stringify({ searchResults: searchResults }))
  } catch (err) {
    return callback(err)
  }
}

解説

特に難しいことはしてないが、大事なのは次の3つ。
この3つを守れば上記のプログラムでスクレイピングしているとこをお好きなように弄っても動くはずです。

必要なのはパッケージは3つでpuppeteerのバージョンには注意

まずプログラムを見てわかるとおり、@serverless-chrome/lambdachrome-remote-interfacepuppeteerの3つを使用している。その中でもpuppeteerは現在1.5.0がリリースされているがそのバージョンでは動かないので、1.4.0で動作させる必要がある。
(逆に動いたよっていう方いらっしゃったら教えてください)

1.10.0で動くことを確認したので、修正しています。

puppeteerのchromiumは使用しない

普通なら使用してもいいのだが、今回はAWS Lambdaで動かすという条件がある。AWS Lambdaで登録できるプログラムサイズは50Mバイト以内という条件があるため、それをクリアするためにpuppeteerのchromiumを使用(ダウンロード)してはならない。
そこでpuppeteerのchromiumを使用しないようにするために.npmrcを作成し、以下の記述をしておく。

.npmrc
puppeteer_skip_chromium_download=true

これで使用されなくのでOKです。(もちろん環境変数にセットするという手もあるが、誰でも同じ環境になるようにするにはファイルで書いておいた方が吉)

https://github.com/GoogleChrome/puppeteer/issues/2270

日本語表示

今回はやってないが、参考記事通りにWebフォントいれたら表示されると思う。
この辺も含めて冒頭で触れたPhatomJSをカスタムビルドしている理由の1つ。

私自身で日本語フォントの適用をやってみたが、UserAgentが設定されていないとフォントが反映されなかったので、そこは注意してほしい。

await page.setUserAgent('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36')

// If User Agent is not set, the font will not be reflected, so User Agent must be set
await page.evaluate(() => {
    var style = document.createElement('style')
    style.textContent = `
        @import url('//fonts.googleapis.com/css?family=Source+Code+Pro');
        @import url('//fonts.googleapis.com/earlyaccess/notosansjp.css');
        div, input, a{ font-family: 'Noto Sans JP', sans-serif !important; };`
    document.head.appendChild(style)
})
await page.waitFor(1000) // Wait until the font is reflected

参考記事

本記事はこちらを参考にさせて頂き書いております。

https://www.pressmantech.com/tech/serverless/4417

chimame
finergy-a-tm
大阪府大阪市北区角田町8番1号 梅田阪急ビル オフィスタワー35F
https://finergy.a-tm.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away