SeleniumからHeadless Chromeを使ってみた

  • 64
    いいね
  • 2
    コメント

先日PhantomJSのVitalyさんがメンテナーを引退するという話が話題になっていました。ヘッドレスなブラウザーを気軽に使う手段としてPhantomJSにはお世話になりました。今後はHeadless Chromeを使って欲しいとのことなので、試してみました。

Node.jsを使うサンプルは多く見つかりますが、諸事情でPythonを使いたかったので、ここではSelenium経由でHeadless Chromeを使います。

Headless Chromeとは

Google Chrome 59から使えるようになる予定の、画面を表示せずに動作するモードです。自動テストやWebスクレイピングなどに役立ちます。

2017年4月28日現在、Mac版とLinux版のDevチャネルまたはCanaryチャネルで使用できるようです。私はMac版のCanaryチャネルで試しました。Windows版のCanaryチャネルでも試してみましたが--headlessを指定しても画面が表示されてしまいました。そのうち使えるようになると思います1

とりあえずNode.jsのchrome-remote-interfaceから使うのが簡単かつ情報も多いので、ここから試してみると良いでしょう。

ちなみに、昔からXvfbなどの仮想ディスプレイにChromeを起動してヘッドレスで使っていた例も多くあるようです。ググる時はどちらの意味で使われているか確認しましょう。

SeleniumからHeadless Chromeを使う

Headlessだからと言って、通常のChromeを使うときと大きく変わるわけではありません。SeleniumからChromeDriverを通して、Chromeを操作します。ChromeのWebDriverの作成時に引数としてChromeOptionsを渡し、その中で実行するChromeのパスや引数を指定します。

環境

試した環境は以下のとおりです。

  • OS X El Capitan
  • Google Chrome Canary 60.0.3082.0
  • ChromeDriver 2.29
  • Python 3.6.0
  • Selenium 3.4.0

準備

前提: Python 3.6はインストールされている。

  1. Google Chrome Canaryをインストールする(Stableチャネルで--headlessが使えるようになったら不要なはず)。CanaryはStableと共存できる。
  2. ChromeDriverをダウンロードして、PATHの通ったところに置く。
  3. Seleniumをインストールする(ここでは仮想環境を使う)。
(venv) $ pip install selenium

サンプルコード

Google検索を行います。Pythonクローリング&スクレイピングのサンプルコードを改変したもので、PhantomJSを使っていた箇所をHeadless Chromeに置き換えてみました。

selenium_google.py
import time

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.chrome.options import Options

options = Options()
# Chromeのパス(Stableチャネルで--headlessが使えるようになったら不要なはず)
options.binary_location = '/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary'
# ヘッドレスモードを有効にする(次の行をコメントアウトすると画面が表示される)。
options.add_argument('--headless')
# ChromeのWebDriverオブジェクトを作成する。
driver = webdriver.Chrome(chrome_options=options)

# Googleのトップ画面を開く。
driver.get('https://www.google.co.jp/')

# タイトルに'Google'が含まれていることを確認する。
assert 'Google' in driver.title

# 検索語を入力して送信する。
input_element = driver.find_element_by_name('q')
input_element.send_keys('Python')
input_element.send_keys(Keys.RETURN)

time.sleep(2)  # Chromeの場合はAjaxで遷移するので、とりあえず適当に2秒待つ。

# タイトルに'Python'が含まれていることを確認する。
assert 'Python' in driver.title

# スクリーンショットを撮る。
driver.save_screenshot('search_results.png')

# 検索結果を表示する。
for a in driver.find_elements_by_css_selector('h3 > a'):
    print(a.text)
    print(a.get_attribute('href'))

driver.quit()  # ブラウザーを終了する。

以下のように実行すると、ブラウザーの画面が表示されない状態で検索結果が出力されました。

(venv) $ python selenium_google.py
Python - ウィキペディア
https://ja.wikipedia.org/wiki/Python
Python チュートリアル — Python 3.6.1 ドキュメント
http://docs.python.jp/3/tutorial/
Python基礎講座(1 Pythonとは) - Qiita
http://qiita.com/Usek/items/ff4d87745dfc5d9b85a4
初心者でもほぼ無料でPythonを勉強できるコンテンツ10選 - paiza開発日誌
http://paiza.hatenablog.com/entry/2015/04/09/%E5%88%9D%E5%BF%83%E8%80%85%E3%81%A7%E3%82%82%E3%81%BB%E3%81%BC%E7%84%A1%E6%96%99%E3%81%A7Python%E3%82%92%E5%8B%89%E5%BC%B7%E3%81%A7%E3%81%8D%E3%82%8B%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%8410
【入門者必見】Pythonとは?言語の特徴やシェア、仕事市場を徹底解説 | 侍 ...
http://www.sejuku.net/blog/7720
Pythonに咬まれるな : 注意すべきセキュリティリスクのリスト | プログラミング ...
http://postd.cc/a-bite-of-python/
Pythonとは - はてなキーワード - はてなダイアリー
http://d.hatena.ne.jp/keyword/Python
Python入門から応用までの学習サイト
http://www.python-izm.com/
Pythonで学ぶ 基礎からのプログラミング入門 (1) Pythonでプログラミングを ...
http://news.mynavi.jp/series/python/001/
Download Python | Python.org
https://www.python.org/downloads/

PhantomJSとの差異など

  • 実行中に画面は表示されないが、DockにはChromeのアイコンが表示される。
  • 明示的にdriver.quit()としないとChromeは終了しない。
  • PhantomJSだと検索語を入力して送信した時にonloadまで待ってくれていたが、ChromeだとAjaxで遷移するので別途待つ必要があった(これはGoogleの挙動の違いによるものでChromeやGoogleの問題ではない)。
  • ヘッドレスモードだと、save_screenshot()で撮影したスクリーンショットが1x1の画像になってしまった。何かオプションが必要なのかも。

まとめ

少なくともOS Xでは気軽にHeadless Chromeを使用できました。Stableチャネルで使用できるようになればさらに簡単です。--headlessオプションを取り除けば画面が表示されるので、デバッグしやすそうなのも嬉しいです。