Python
Selenium
RaspberryPi
headless-chrome

Raspberry pi3上でChromeのheadlessモードによる小型低電力&自動化環境への第一歩

動機

Raspberry piの小型低電力の特性を生かした活用方法の一つとして、headlessブラウザを使った自動化環境にチャレンジして見たいと思います。

一昔前だと、VXFD仮想ディスプレイ+pyvirtualdisplayの環境で、ブラウザにiceweasel(現:Firefox)を使って実現していたようで、その辺りの記事はよく見かけます。
今回、Chromeに実装されたheadlessモードを使ってやってみました。
とはいえ、情報が少なく試行錯誤の連続でしたが、しばらくやってから冷静に考えると結構簡単に解決したので手順も含めて共有します。

試行錯誤履歴

  • Firefox + VXFD + pyvirtualdisplay環境
    • VXFDはブラウザ標準のheadlessではないので、やり方だけググって見送り
  • Firefoxでのheadless
    • apt-getで取得できるFirefoxバージョンが52で、まだ-headlessに対応していない
    • しかも、GeckoDriverは64bit対応版しか公開されておらず、32bitモードで動くraspberry piでは扱えず
  • Chromium-browser + ChromeDriverの組み合わせ

行き着いた先

色々試して路頭に迷っていたところ、ふとaptでChromeDriveがあるんじゃね?と思って探すとあったんですね。灯台下暗しと言いますか・・・
chromium-browserがaptで取得できるのだから当たり前といえば当たり前なんでしょうが、取り組み当初は思いつきませんでした。ちゃんと全体を見渡してから一つずつ試さないとダメですね。
さて、気を取り直して以下、環境構築手順とサンプルプログラム。

最終的な環境

  • Raspberry pi3
  • Raspbian Stretch lite
  • Chromium v65
  • ChromeDriver v2.35
  • Python2.7
  • Selene

 環境構築

Chrome, ChromeDriverのインストールと設定

# chromeブラウザインストール(2018.7.10時点でv65)
$ sudo apt-get install chromium-browser

# v65のChromeに対応したChromeDriveをインストール
$ sudo apt-get install chromium-chromedriver

# chromedriverが環境パス上に無いので、/usr/bin/下にシンボリックリンクを張っておく。
# コードでパスを指定するので別にやらなくても良い。
$ sudo ln -s /usr/lib/chromium-browser/chromedriver /usr/bin/

# 日本語フォントが無いのでインストール
$ sudo apt-get install fonts-ipafont-gothic fonts-ipafont-mincho

インストールしたバージョンは下記。

$ chromium-browser --version
Chromium 65.0.3325.181 Built on Raspbian , running on Raspbian 9.4

$ chromedriver --version
ChromeDriver 2.35 (0)

seleneインストール

Javaでよく使われるSeleniumラッパーでSelenideというものがありますが、それをPython向けにポートしたSeleneというのがあります。
Seleniumの面倒なところを吸収してくれているのでオススメのライブラリです。
下記の手順でpipを使ってインストールします。

$ sudo apt-get install python-pip
$ pip install selene --pre

サンプルプログラム(python)

from selene.browsers import BrowserName
from selene.api import *
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
import traceback


def main():
    try:
        config.browser_name = BrowserName.CHROME
        chrome_option = webdriver.ChromeOptions()
        chrome_option.add_argument('--headless')
        chrome_option.add_argument('--disable-gpu')
        driver = webdriver.Chrome(executable_path="/usr/bin/chromedriver", chrome_options=chrome_option)
        browser.set_driver(driver)
        browser.open_url("http://www.yahoo.co.jp")
        driver.save_screenshot('screenshot.png')
        browser.quit()
    except:
        print traceback.format_exc()
        browser.quit()

if __name__ == '__main__':
    main()

最後に

このサンプルプログラムを実行すると、実行フォルダにscreenshot.pngが作成されます。
ここまでできればSeleniumの要領でページ操作をすれば色々とできそうです。
まだ複雑なJavascriptが存在するようなページ操作などは試せていませんが、Chrome v65なので問題になるケースは少ないのではないかと思っています。
実行速度も比較検証はしていませんが、時間的にシビアな処理をさせるつもりも無いので特に問題ないでしょう。

このくらいであればRaspberry pi Zeroでも動くかもしれませんが、いずれチャレンジしてみようと思います。どなたかすでに試された方がいれば共有してくれると嬉しいです。