Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save sys9kdr/477d4c44b51c722331951c3f4b0b0c13 to your computer and use it in GitHub Desktop.
Save sys9kdr/477d4c44b51c722331951c3f4b0b0c13 to your computer and use it in GitHub Desktop.
Puppeteerがクローリングに使えそう

この記事はWebスクレイピング Advent Calendar 2017の17日目の記事です。puppeteerでクローリングします。

Google Chrome(Chromium)でクローリングをやる

SPAみたいなちょっと凝ったWebサイトをクローリングするときは一昔前はSelenium + PhantomJSあたりが鉄板でしたが、今後はSelenium + Headless ChromeもしくはPuppeteer + Headless Chromeが主流となっていく見通しです。 (HeadlessとはGUIアプリケーションのGUIを介さないモードのことです。)

前者についてはWeb上に情報も多いですが、Puppeteerでクローリングする話をそんなに見ない気がするのでクローリングの歴史を踏まえてやってみます。

一昔前のクローリング

古くはサーバーでPerlなりPHPなりRoRなりが吐いた、あるいは静的に配信されたHTMLがえっちらおっちらとネットワーク越えて手元のブラウザにやってきて、それをクライアント側でよっこらしょとレンダリングするというのがほぼ唯一のWebサイトのアーキテクチャでした。現在も往時ほど支配的ではないにしても、このようなアーキテクチャのサイトが大半でしょう。

このアーキテクチャだとHTMLがそのままもらえるため、クローリングやスクレイピングをするときにはHTMLのことだけ考えていれば情報が取得できます。正規表現やパーサーでほぼすべての用がなせるでしょう。単純なテキスト処理プログラムだけで話が終わっていたため、このようなWebサイトのクローリングはだいたいメモリ消費量やCPU使用率に優れています。

現代のクローリング

ときは移ろい、Ajaxの誕生でサーバーはとりあえずHTML全部吐いて渡してくれるという常識が覆り、さらにはSPAの流行も手伝いWebサイトを巡回してコンテンツを取得するのにJavaScriptを処理する必要が出てきました。こうなると旧来型のHTMLを素朴に処理するだけでは対処しきれない場面が多く出てきます。

そこで、こういったアーキテクチャを採用するWebサイトに対してはSelenium + PhantomJS(ヘッドレスWebブラウザ、登場時は希少だった)はじめ自動化ツール+Webブラウザによるクローリングが一般化してきます。

そこからもろもろあってHeadless Chromeが登場します。デファクトだったPhantomJSはQtWebKitを利用した ブラウザのような何か で現実で使われているブラウザとは若干の違いがありました。それに対して、モバイルは言うに及ばず、デスクトップでも多大なシェアを誇るChromeを(GUIのオーバーヘッドなしに)自動化に使えたため、Headless Chromeに人気が集中します。後追う形でHeadless Firefoxも登場しています。

今後、WebテストやクローリングにはHeadless Chromeが支配的なポジションを占めていくのではないでしょうか。

手を動かす

現状は把握できたので早速手を動かしていきましょう。今回はSeleniumでもPuppeteerでもどっちでもよかったのですが、Headless Chrome向けで使うのに手間の少ないPuppeteerを使うことにします。

npm install puppeteerがつづりが難しくて最大の難関になっていますが、特にブラウザを別途取得したりする必要もなくサクサク書けます。

Chromeの開発者向けサイトから記事一覧、記事の画像を取得する操作を例に一通り書いてみます。(API参照)

// main.js
// npm install puppeteer@0.13.0
const pptr = require('puppeteer');

async function run(){
    // ブラウザを起動する
    const browser = await pptr.launch({
        args: ['--lang=ja,en-US,en'] // デフォルトでは言語設定が英語なので日本語に変更
    })

    // ページつくる
    const page = await browser.newPage()

    // サイズ決める
    await page.setViewport({ width: 720, height: 600 })

    // Chromeの開発者向け資料Webサイトに移動
    await page.goto('https://developer.chrome.com/home/platform-pillar')

    // ページタイトル取得
    console.log(await page.title())

    // スクリーンショット取っちゃう
    await page.screenshot({path: 'sample1.png', fullPage: true})

    // ページ遷移してスクリーンショット取る
    await page.click('article a:not([href^=http])') // セレクタ指定してクリックだけと楽
    await page.screenshot({path: 'sample2.png', fullPage: true})

    // 終了
    await browser.close()
}

run() //node main.jsで実行

SPAでもやってみましょう。Angularの公式サイトで検索してみます。

const pptr = require('puppeteer');

async function run(){
    const browser = await pptr.launch({})
    const page = await browser.newPage()

    await page.setViewport({ width: 640, height: 720 })

    await page.goto('https://angular.io')
    console.log(await page.title())

    await page.type('input[aria-label=search]', 'cli') // 要素に文字列cliを入力
    await page.waitFor(5000) // sleep
    await page.screenshot({path: 'sample3.png'})

    await browser.close()
}

run()

SPAもほとんど何も考える必要もなくばっちりです。 そのままだと早すぎて検索結果が返ってこないので今回はwaitを入れました。

2例とも大したコードではないので魅力や使い勝手は伝わりづらいかもしれませんが、ブラウザ操作の自動化に関して気にするところが少なくていいのはありがたいところです。 Puppeteerを使うとクローリング回り特に意識せず雑に書けるのは大きな魅力ではないでしょうか。

今回は紹介しませんでしたが、かなり自由度の高い操作ができる強力さも魅力です。

クローリングで何を使おうか迷ったときはPuppeteerから始めるとJavaScriptを多用するページに特に考えずに対応できるためおすすめです。

おまけ

puppeteerにはpyppeteerという有志のPythonポートがあります。クローリング、スクレイピングといえばPythonみたいなところもあるし、こっちも要チェックですね。

miyakogi/pyppeteer https://github.com/miyakogi/pyppeteer


参考文献

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment