Puppeteerの使い方(スクレイピング, フロントテストで活用)

Puppeteerは、Headless Chromeを操作できるNode.jsのライブラリです。Chrome DevToolsチームがメンテナンスを行なっており、スクレイピングやフロントテストに活用できます。ここでは、Puppeteerの基本的な使い方を確認します。

前知識

  • ヘッドレスブラウザとは?
    • GUI(画面)を持たないブラウザです。
  • Chromiumとは?
    • Google Chrome の元となっているオープンソースのブラウザです。
    • Chromium - Wikipedia

Puppeteerをインストール

Chromiumを含める

nodeのversionは以下の通りです。

$ node -v
v8.10.0

Puppeteerをインストールします。

$ yarn add puppeteer
$ npm install --save puppeteer

Puppeteerをインストールすると Chromium も同時にダウンロードされます。
macでインストールした場合、以下フォルダに Chromium が存在します。

$ ls -l node_modules/puppeteer/.local-chromium/mac-624492/chrome-mac/Chromium.app/Contents/MacOS
total 368
-rwxr-xr-x  1 xxx  xxx  186028 Feb 22 12:02 Chromium

Chromiumを含めない

Chromium は容量が大きいので注意が必要です。例えば AWS Lambda で利用する場合、Chromium を含めてしまうとデプロイパッケージの容量制限に引っかかります。

そこで、 Chromium を含めないでPuppeteerをインストールする方法があります。

方法1

PUPPETEER_SKIP_CHROMIUM_DOWNLOAD という環境変数を設定した状態でインストールすると Chromium が含まれません。

$ PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 yarn add puppeteer

方法2

puppeteer-core という Chromium を含まないパッケージがあります。

$ yarn add puppeteer-core

動作例

sample1.js というファイルで、puppeteerを利用してみます。

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    headless: false,  // 動作確認するためheadlessモードにしない
    slowMo: 500  // 動作確認しやすいようにpuppeteerの操作を遅延させる
  })
  const page = await browser.newPage()

  await page.goto('https://www.google.com/')
  await page.type('input[name=q]', 'スカイツリー', { delay: 100 })
  await page.click('input[type="submit"]')
  await page.waitForSelector('h3 a')
  await page.screenshot({ path: 'screenshot/sample1.png' })

  await browser.close()
})()

以下の処理を行っています。

  • https://www.google.com/ にアクセスして、
  • スカイツリー の検索結果のスクリーンショットをとり、
  • screenshotディレクトリ に保存

実行します。

$ mkdir screenshot
$
$ node sample1.js
$
$ ls screenshot
sample1.png
620-javascript-puppeteer_sample1.gif

headless: falseとしたので、画面上で動作を確認することができます。

要素取得

PageクラスとElementHandleクラス

以下のメソッドを利用して、要素を取得できます。

メソッド Class: Page Class: ElementHandle 概要
evaluate × JavaScriptで処理できる。
$ 要素( ElementHandle )を取得。
内部で querySelector が利用されいている。
$$ 複数の要素( Array<ElementHandle> )を取得。
内部で querySelectorAll が利用されいている。
$eval JavaScriptで処理できる。
Elementプロパティ を利用できる。
$$eval JavaScriptで処理できる。
Elementプロパティ を利用できる。

利用例

要素取得の実装例を示します。

<div id="result">
  <div class="item">
    <a href="http://xxx" data-test="aaaa"></a>
    <p>xxxxxxxx</p>
  </div>
  <div class="item">
    <a href="http://yyy" data-test="bbbb"></a>
    <p>yyyyyyyy</p>
  </div>
  <div class="item">
    <a href="http://zzz" data-test="cccc"></a>
    <p>zzzzzzzz</p>
  </div>
</div>

上記HTMLから要素を取得する処理を実装します。

const puppeteer = require('puppeteer')
const path = require('path')

const testItem = async page => {
  console.log('############ 要素を1つ取得 ############')

  // ElementHandleクラスのインスタンスを取得
  const item = await page.$('#result div.item')
  console.log(await (await item.getProperty('innerHTML')).jsonValue())
  console.log('--------------------------------------')
  console.log(await (await item.getProperty('textContent')).jsonValue())
}

const testItems = async page => {
  console.log('############ 要素を1つ取得 ############')

  // Array<ElementHandle> を取得
  const items = await page.$$('#result div.item')
  console.log(items.length)

  for (const item of items) {
    // data属性取得
    console.log('--------------------------------------')
    console.log(await item.$eval('a', element => element.getAttribute('data-test')))

    // href取得
    const aTag = await item.$('a')
    const href = await aTag.getProperty('href')
    const url = await href.jsonValue()
    console.log(url)
  }
}

(async () => {
  const browser = await puppeteer.launch()
  // Pageクラスのインスタンスを取得
  const page = await browser.newPage()
  await page.goto(`file:${path.join(__dirname, '/test_html/sample.html')}`)
  await testItem(page)
  await testItems(page)
  await browser.close()
})()

実行結果は以下の通りです。

$ node sample2.js 
############ 要素を1つ取得 ############

    <a href="http://xxx" data-test="aaaa"></a>
    <p>xxxxxxxx</p>
  
--------------------------------------

    
    xxxxxxxx
  
############ 要素を1つ取得 ############
3
--------------------------------------
aaaa
http://xxx/
--------------------------------------
bbbb
http://yyy/
--------------------------------------
cccc
http://zzz/

サーバーレスで実行する方法

Cloud Functions

サポートされているようです。

https://cloud.google.com/blog/products/gcp/introducing-headless-chrome-support-in-cloud-functions-and-app-engine

AWS Lambda

Chromium が必要とする共有ライブラリがLambda上に存在しないので対策が必要です。

serverless-chrome というのを利用すると、Lambda上でも実行できます。

serverless-chrome を利用して、Lambda上で動かすための下準備をしてくださったリポジトリがあったので、こちらを活用してみると良いと思います。

https://github.com/sambaiz/puppeteer-lambda-starter-kit

参考・補足

【エンジニア向け】仕事を見つける方法

転職する

転職エージェントを活用する

転職サイトの場合、自身でサイト上から企業を探す必要があります。 一方「レバテックキャリア」 などの転職エージェントの場合、エージェントが企業を紹介してくれます。エージェントが間に入ることにより、日程調整や、条件交渉などもサポートしてくれます。

転職ドラフトを活用する

転職ドラフト」は、 企業がITエンジニアをドラフトという形で指名するサービスです。年収が最初に提示されるなどのメリットがあります。 ただ、初回登録時にレジュメ作成が必要で、すでにエンジニア経験が豊富にあるエンジニア向けのサービスかと思います。 レジュメ作成が手間ですが、自身のキャリアを見直す機会になり、他の仕事探しにも役立つはずです。

エンジニア転職保証のあるスクールを活用する

ある程度、開発経験のあるかたであれば、独学で必要なスキルを身につけることができるはずです。ただ、別業種からエンジニアに転職したい場合など、1から独学で学ぶのはハードルが高いです。そういった方は、スクールの活用を検討しても良いと思います。 「TechAcademy」は、エンジニア転職保証コースを提供しています。給付金制度の対象講座として認定されているため、金銭面の負担も抑えることができます。

フリーランスとして活動する

レバテックフリーランス」「ITプロパートナーズ」「ギークスジョブ」は、フリーランスエージェントサービスです。 エージェントによって、支払いサイトなど細かい違いはありますが、まずは良い案件を見つけることが重要です。 登録自体は無料なので、複数エージェントに登録して、より多くの案件を紹介してもらうのがおすすめです。

logo
わくわくBank.
技術系の記事を中心に、役に立つと思ったこと、整理したい情報などを掲載しています。