SeleniumからStableになったHeadless Chrome/Firefoxを使ってみる

1年ほど前に以下の記事を書きましたが、StableなGoogle Chromeでヘッドレスモードが使えるようになり、今となっては紛らわしい記述もあるので、新しく記事を書きます。ついでにFirefoxのヘッドレスモードも触ってみました。

SeleniumからHeadless Chromeを使ってみた - Qiita
https://qiita.com/orangain/items/db4594113c04e8801aad

Headless Chromeとは何か、なぜ注目されているかといった背景についてはこの記事を参照ください。

## SeleniumからHeadless Chromeを使う

SeleniumからGoogle Chromeを操作するにはChromeDriverが必要です。

```
[Selenium] ---> [ChromeDriver] ---> [Google Chrome]
```

### 環境

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

* macOS Sierra 10.12.6
* Google Chrome 66.0.3359.139 (Stable)
* ChromeDriver 2.38.552518
* Python 3.6.4
* Selenium 3.11.0


### 準備

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

1. Google Chromeのバージョンに対応する[ChromeDriver](https://sites.google.com/a/chromium.org/chromedriver/downloads)をダウンロードして、PATHの通ったところに置く。
2. Seleniumをインストールする（ここでは仮想環境を使う）。

```
(venv) $ pip install selenium
```

### サンプルコード

Google検索を行います。[Pythonクローリング&スクレイピング](http://orangain.hatenablog.com/entry/scraping-book)のサンプルコードを改変したもので、PhantomJSを使っていた箇所をHeadless Chromeに置き換えてみました。

```selenium_chrome_google.py
from selenium.webdriver import Chrome, ChromeOptions
from selenium.webdriver.common.keys import Keys

options = ChromeOptions()
# ヘッドレスモードを有効にする（次の行をコメントアウトすると画面が表示される）。
options.add_argument('--headless')
# ChromeのWebDriverオブジェクトを作成する。
driver = 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)

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

# スクリーンショットを撮る。
driver.save_screenshot('chrome_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とは？言語の特徴から網羅的に徹底解説 | 侍 ...
https://www.sejuku.net/blog/7720
Welcome to Python.org
https://www.python.org/
Pythonとは？特徴やできること、ダウンロード方法と文法を解説 | TECH ...
https://tech-camp.in/note/technology/33753/
Python基礎講座(1 Pythonとは) - Qiita
https://qiita.com/Usek/items/ff4d87745dfc5d9b85a4
Pythonとは？何に使えるの？Pythonの特徴や使い道を…｜Udemy メディア
https://udemy.benesse.co.jp/development/python.html
Top - python.jp
https://www.python.jp/
今さら聞けない！Pythonとは【初心者向け】 | TechAcademyマガジン
https://techacademy.jp/magazine/15507
Pythonは今のうちに習得すべき？『スラスラわかるPython』著者・岩崎さんと ...
https://codezine.jp/article/detail/10329
Pythonで最初に知っておきたかったことのまとめ【初心者向け】 - karaage ...
http://karaage.hatenadiary.jp/entry/2017/12/27/073000
```

以前はヘッドレスモードでもDockにChromeのアイコンが表示されていましたが、表示されなくなりました。ただし一瞬Dockが揺れ動きました。


## SeleniumからFirefoxのヘッドレスモードを使う

ついでなのでFirefoxのヘッドレスモードも使ってみます。SeleniumからFirefoxを操作するにはGeckoDriverが必要です。

```
[Selenium] ---> [GeckoDriver] ---> [Firefox]
```

### 環境

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

* macOS Sierra 10.12.6
* Firefox 59.0.2
* Geckodriver 0.20.1
* Python 3.6.4
* Selenium 3.11.0

### 準備

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

1. [GeckoDriver](https://github.com/mozilla/geckodriver/releases)をダウンロードして、PATHの通ったところに置く。
2. Seleniumをインストールする（ここでは仮想環境を使う）。

```
(venv) $ pip install selenium
```


### サンプルコード

Google検索を行います。[Pythonクローリング&スクレイピング](http://orangain.hatenablog.com/entry/scraping-book)のサンプルコードを改変したもので、PhantomJSを使っていた箇所をFirefoxのヘッドレスモードに置き換えてみました。

```selenium_firefox_google.py
from selenium.webdriver import Firefox, FirefoxOptions
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

options = FirefoxOptions()
# ヘッドレスモードを有効にする（次の行をコメントアウトすると画面が表示される）。
options.add_argument('-headless')
# FirefoxのWebDriverオブジェクトを作成する。
driver = Firefox(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)

# 検索結果の要素が表示されるまで待つ。
WebDriverWait(driver, 10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, 'h3 > a')))

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

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

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

なお、Firefoxでは検索語を入力して送信した後、ページのロード完了まで待ってくれなかったので、WebDriverWaitを使って検索結果の要素が表示されるまで待つようにしました。

### 実行結果

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

```
(venv) $ python selenium_firefox_google.py
Python - ウィキペディア
https://ja.wikipedia.org/wiki/Python
Welcome to Python.org
https://www.python.org/
専門知識いらず！Pythonとは？言語の特徴から網羅的に徹底解説 | 侍 ...
https://www.sejuku.net/blog/7720
Pythonとは？特徴やできること、ダウンロード方法と文法を解説 | TECH ...
https://tech-camp.in/note/technology/33753/
Python基礎講座(1 Pythonとは) - Qiita
https://qiita.com/Usek/items/ff4d87745dfc5d9b85a4
Pythonとは？何に使えるの？Pythonの特徴や使い道を…｜Udemy メディア
https://udemy.benesse.co.jp/development/python.html
Top - python.jp
https://www.python.jp/
今さら聞けない！Pythonとは【初心者向け】 | TechAcademyマガジン
https://techacademy.jp/magazine/15507
Pythonは今のうちに習得すべき？『スラスラわかるPython』著者・岩崎さんと ...
https://codezine.jp/article/detail/10329
Pythonで最初に知っておきたかったことのまとめ【初心者向け】 - karaage ...
http://karaage.hatenadiary.jp/entry/2017/12/27/073000
```

一瞬Dockが揺れ動くのはChromeと同じでした。

## まとめ

少なくともmacOSでは気軽にChromeとFirefoxのヘッドレスモードを使うことができました。