初めまして、気づいたらバイトの中で一番古株になっていたイタヤです。

今回はchrome ヘッドレスを用いたスクレイピング手法について説明したいと思います。

chrome ヘッドレスとは

普段みなさんはどのようなブラウザを使っているでしょうか?

「Google Chrome」「Firefox」「Internet Explorer」など様々だと思います。

chrome ヘッドレスとは、その中の「Google Chrome」を画面表示せず実行するものです。 ※今回は、このchrome ヘッドレスをスクレイピングに用いますが、その用途以外にもブラウザテスト・業務の自動化(RPA)などにも用いられています。

そもそも何故chrome ヘッドレスクローム?

Webページの中には、JavaScriptを用いて動的にHTMLを生成している場合があります。ご存知の方も多いと思いますが、JavaScriptはブラウザで表示された時に実行される言語です。そのため、少し前の記事で紹介している「open-uri」や「net/http」ではJavaScriptが実行されないため、JavaScript実行前のHTMLを取得することになってしまいます。 しかし、時には「JavaScriptが実行された後のHTMLを取得したい」という場合もあるでしょう。そういった時に、このchrome ヘッドレスが役に立つのです。

前述した通り、JavaScriptはブラウザで実行される言語です。そして、このchrome ヘッドレスは当たり前ですがブラウザです。そのため、これを用いると先ほどいっていた「JavaScriptが実行された後のHTML」が取得できるのです。

さらに、chrome ヘッドレスを操作することの利点はもう1つあります。それは、こちらが指定したJavaScriptも実行できるという点です。「open-uri」や「net/http」でログイン後のHTMLを取得する際には、実際にログインフォームに値を入力してログインしているわけではなく、裏側で行われている通信内容を確認し、そのPOSTリクエストを確認し…と少し解析が必要です。しかし、このchrome ヘッドレスを用いると自分で動かしたいJavaScriptを記述・実行できるので、シンプルにログインフォームに値を入れて「ログイン」ボタンを押すという命令を記述するだけでログイン後のHTMLが取得できるのです。

用意するもの

  • Mac

  • Google Chrome最新版(現在:65.0.3325.181)

  • [オプション]Ruby(2.3.4)

  • [オプション]Chromedriver

    chrome ヘッドレスを実行するだけであればGoogle Chromeの最新版があれば大丈夫です。

    そのほかのRubyやChromedriverはスクレイピングで用いるときに使うものです。

Ubuntu/CentOSの環境構築については、別に記事にて紹介しています。

chrome ヘッドレスの起動設定

以下は、公式ドキュメントに乗っている手順 (https://developers.google.com/web/updates/2017/04/headless-chrome?hl=ja

chromeのエイリアスを設定

$ alias chrome='/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome'

※毎回記述するのが面倒なのでbash_profileに記述しておくと良い

chromeの起動

まずは、普通にコマンドラインからchromeを起動して見ましょう。

$ chrome

これで、普通のGoogle Chromeが新しいウィドウで起動したらaliasがきちんと設定されている証拠です。

chrome ヘッドレスの起動

上記のコマンドが問題なく実行できたらヘッドレス実行を試して見ましょう。

$ chrome --headless --disable-gpu --dump-dom https://www.chromestatus.com/'

ターミナル上にDOMツリーが表示されたら成功です。

Chrome ヘッドレスを用いたスクレイピング

ここからは、そのchrome ヘッドレスを使ってスクレイピングを行う方法を紹介します。

サンプルとして、サイトからメニュー名の一覧を取得するコードを紹介します。 このサイトはjQueryで動的に生成されているので、今までのopen-uriなどでは取得できません。 (※時間に余裕のある方は、試しにopen-uriで挑戦してみると良いでしょう。できなくはないですが、かなり工夫が必要です。)

chromedriverの設定

※chromedriverは更新されていくので、必要に応じてバージョン番号を変更してください(現在最新2.37) 最新バージョンの確認は以下のリンクにてできます。 https://sites.google.com/a/chromium.org/chromedriver/downloads

  1. まずはchromedriverをダウンロード

    https://chromedriver.storage.googleapis.com/index.html?path=2.37/

    このURLにchromedriverがあるのでダウンロードします。 ※Macの場合は「chromedriver_mac64.zip」です。

  2. zipファイルからchromedriverを取得する。

  3. chromedriverをパスの通っている位置に移動します。(/usr/local/bin/chromedriverなど)

  4. 実行できるか確認

    $ chromedriver -v
    ChromeDriver 2.37.544337 (8c0344a12e552148c185f7d5117db1f28d6c9e85)
    

    このようにバージョンの表記が出たらchromedriverの設定は完了です。

rubyでコードを記述

Gemfile

gem 'selenium-webdriver'
gem 'nokogiri'

crawler.rb(メールアドレス・パスワードは自分のアカウントのものを入力)

require 'nokogiri'
require 'selenium-webdriver'
ua = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36"
#ブラウザ立ち上げモード
#caps = Selenium::WebDriver::Remote::Capabilities.chrome('chromeOptions' => {args: ["--user-agent=#{ua}", 'window-size=1280x800']})
#ヘッドレスモード
caps = Selenium::WebDriver::Remote::Capabilities.chrome('chromeOptions' => {args: ["--headless","--no-sandbox", "--disable-setuid-sandbox", "--disable-gpu", "--user-agent=#{ua}", 'window-size=1280x800']})
driver = Selenium::WebDriver.for :chrome, desired_capabilities: caps

#スクレイピングしたいサイト
driver.navigate.to "https://rootersample.web.fc2.com/drink.html"
sleep 2

#Nokogiriを用いてHTMLをパースする
doc = Nokogiri::HTML.parse(driver.page_source, nil, 'utf-8')
#メニュー名を取得
doc.css('.col-lg-4').each do |div|
    p div.css('h3')[0].text
end

bundle installする

$ bundle install --path .bundle

クローラーの実行

$ bundle exec ruby crawler.rb

結果

"ドリンク1"
"ドリンク2"
"ドリンク3"
"ドリンク4"
"ドリンク5"
"ドリンク6"
"ドリンク7"
"ドリンク8"
"ドリンク9"

メニュー名の一覧が表示されたら成功です。

まとめ

今回はMac環境でのchrome ヘッドレスを用いたスクレイピング手法についてまとめました。普通のRubyを用いたスクレイピングとは違い、外部のプログラム(google chrome)を呼び出すプログラムなので、rubyのコードが合っていても呼び出しに失敗している場合などもあるので、ソースコードだけでなく環境変数等も確認するようにしましょう。 これから、クローラーを用いたクローリングや、ブラウザを用いたテストの自動化(RPA)を考えている人にも参考にしていただけたら幸いです。