Puppeteer?

こんちには、エンジニアのyoshinoです。
Rubyでクローリングをする時はSeleniumが有名ですが、今回は、2018年春にようやくバージョンも1.0になり、安定稼働をし始めたPuppeteer(パペティア)を紹介します。

PuppeteerはChrome DevTools のチームが開発を行っているNodeライブラリで、ChroniumやHeadless Chromeを動かすことができます。

Seleniumにできることは大抵、Puppeteerで行うことができます。
  • Webスクレイピング
  • ページのスクリーンショットやPDFの取得
  • キーボードからの入力などの自動化(RPA)
  • 最新のJavascriptに対応
クローリングにはRubyとSeleniumだけで充分?
いえいいえ、 Puppeteerにしかできないこともあるんです。


※Seleniumでは使えるPhantomJSはPuppeteerでは利用できません。しかし、Headless Chromeが使える今日、PhantomJSの存在感は確実に小さいものになっています。

Puppeteerのセットアップ

まずはPuppeteerのセットアップを見ていきましょう。
mkdir test_puppeteer
cd test_puppeteer
npm i puppeteer
以上。
一緒に、ChroniumやHeadless Chromeも自動でインストールされます。

これだけです。

PuppeteerはNode.jsのライブラリなので、Node.jsがインストールされていない場合は別途インストールする必要はあります。バージョン7.6.0以上が推奨です。
 

Puppeteerを使ってみよう

test.jsというファイルをサンプルに見てみましょう。
const puppeteer = require('puppeteer');
const fs = require('fs');
(async () => {
// puppeteerを立ち上げます
const browser = await puppeteer.launch();
const page = await browser.newPage();
// pageを目的のURLへ移動します 
await page.goto('https://example.com'); 
// スクリーンショットを取ります 
await page.screenshot({path: 'example.png'}); 
// html全体を取得して保存します 
var html = await page.evaluate(() => { return document.getElementsByTagName('html')[0].innerHTML }); 
await fs.writeFileSync('example.html', html); 

// puppeteerを終了します 
await browser.close(); })();
  実行はnode.jsで以下のように行います。
node test.js

スクリーンショットで取得した”example.png”とHTMLファイルである”example.html”がローカルに保存されていることがわかります。

Puppeteerは実行速度を自由に変えられる

puppeteerにはslowMoというオプションがあり、これにより実行速度を自由に変えることができます。

この設定はセレニウムにはできないことです。

エレメントからエレメントへの推移など機械による自動化は、人間にしてはあまりに速い実効速度になってしまいます。
slowMoを1000程度に設定してあげることで、より人間の動作に近い操作を実現できるかもしれません。
設定は簡単で最初の部分を以下の用に変えてあげるだけです。
const browser = await puppeteer.launch({
   slowMo: 1000 // 1000ms に変更します。
 });

Puppeteer(Node.js)からRubyに値を渡したい!!

Puppeteerでしかできないクローリングサイトが見つかる。
でも、Node.jsは使いにくい。

Rubyが好きだ。

Rubyを使いたい。

Active Recodが使いたい!!

という溢れ出る気持ち。
よくわかります。
キレイな方法ではありませんが、RubyからNode.jsを実行し、その結果をRubyで受け取ることもできます。
html取得部分をNode.jsに分離するようなサンプルを見てみましょう。
rubyのコードです。ファイル名は”test.rb”とします。
open3というgemを使います。
require "open3"
cmd = "node test.js"

Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr|
  puts stdout.read  # stdoutにはhtmlが返ってきます。
end
node.jsはこんな感じになります。
 
const puppeteer = require('puppeteer');
const fs = require('fs');

(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();

await page.goto('https://example.com');
var html = await page.evaluate(() => {
return document.getElementsByTagName('html')[0].innerHTML
});
console.log(html) // rubyへ出力します
await browser.close();
})();

    rubyを実行します。
ruby test.rb
 
rubyからpuppeteerを使うことができました!!

 
puppeteerはGoogleの開発チームにより、日々アップデートされています。
あなたの未知なるWebクローリングへの相棒としてpuppeteerはいかがでしょうか。

また、ヘッドレスプラウザを使用しない、基本的なJavaScript/Node.jsによるスクレイピングについての記事も見ておくと、速度重視のスクレイピングもできるようになりぐっと幅が広がりますよ!