ENGINEER BLOG

ENGINEER BLOG

ChromeのHeadlessモードを試す

ごきげんよう、じんぐうじです。
今回は一部で話題になっているGoogleChromeのheadlessモードを試してみます。

headlessモードというのは端的にいうとGUIでは無くCUIで動作させることです。
これを使うとデスクトップ環境が無いサーバ等でChromeが動かせるようになるので、
ブラウザを使ったテストがしやすくなります!わーい!すごーい!

ひとまず入れてみようと思った

ということで今回はubuntu環境で動かしてみます。
まずはchromeのリポジトリを追加します。

$ echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' > /etc/apt/sources.list.d/google.list
$ wget -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add -
$ apt-get update
Ign:1 http://dl.google.com/linux/chrome/deb stable InRelease
Get:2 http://dl.google.com/linux/chrome/deb stable Release [1189 B]
Get:3 http://dl.google.com/linux/chrome/deb stable Release.gpg [916 B]
Get:4 http://dl.google.com/linux/chrome/deb stable/main amd64 Packages [1207 B]
Hit:5 http://security.ubuntu.com/ubuntu xenial-security InRelease
Hit:6 http://archive.ubuntu.com/ubuntu xenial InRelease
Hit:7 http://archive.ubuntu.com/ubuntu xenial-updates InRelease
Hit:8 http://archive.ubuntu.com/ubuntu xenial-backports InRelease
Fetched 3312 B in 0s (3625 B/s)

追加されましたね!続いてchrome本体です。

$ apt-get install --no-install-recommends google-chrome-stable
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
  adwaita-icon-theme dconf-gsettings-backend dconf-service fontconfig fonts-liberation gconf-service
  gconf-service-backend gconf2-common glib-networking glib-networking-common
<以下略>

と思ったのですが、依存するパッケージがじんぐうじの環境では117個ありました。おおすぎ…
というわけでDockerです。Dockerにしましょう。

コンテナでChromeを動かす

Selenium Standalone Serverのポート(4444/tcp)をホストから触れるようにしてコンテナを起動します。

$ docker run --rm -it -p 4444:4444 ubuntu:latest

コンテナ上で必要なもろもろを導入していきます。

# 必要な諸々を入れる
$ apt-get update
$ apt-get install -y --no-install-recommends wget unzip openjdk-8-jre-headless

# 改めてchromeを入れる
$ echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' > /etc/apt/sources.list.d/google.list
$ wget -O - https://dl.google.com/linux/linux_signing_key.pub | apt-key add -
$ apt-get update
$ apt-get install -y --no-install-recommends google-chrome-stable

$ cd ~
# Selenium Standalone Server
$ wget http://selenium-release.storage.googleapis.com/3.4/selenium-server-standalone-3.4.0.jar

# ChromeDriver
$ wget https://chromedriver.storage.googleapis.com/2.29/chromedriver_linux64.zip
$ unzip chromedriver_linux64.zip

道具はそろったので、Selenium Standalone Serverを起動します。
ちなみにDriverを指定しなければChromeDriverをデフォルトで使用します。

$ java -jar selenium-server-standalone-3.4.0.jar
<略>
2017-05-15 03:56:34.214:INFO:osjs.AbstractConnector:main: Started ServerConnector@754ba872{HTTP/1.1,[http/1.1]}{0.0.0.0:4444}
2017-05-15 03:56:34.215:INFO:osjs.Server:main: Started @524ms
03:56:34.215 INFO - Selenium Server is up and running

動いてるようですね!
これでlocalhost:4444でSelenium Standalone Serverを扱えるはずです。
ということでお次は動作確認をしてみます。

webdriver経由で触る

別セッションでホストへログインし、下記コードを実行して確認しました。
Yahooニュースの1件目のタイトルとURLを取得して、トップページのスクリーンショットを取るものとなります。

require 'capybara'
require 'selenium-webdriver'

Capybara.register_driver :remote_chrome do |app|
  Capybara::Selenium::Driver.new(
    app,
    browser: :remote,
    url: 'http://localhost:4444/wd/hub',
    desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome(
      chromeOptions: {
        args: [
          '--headless',
          '--no-sandbox',
          '--window-size=1366,768'
        ]
      }
    )
  )
end

session = Capybara::Session.new(:remote_chrome)

# yahooトップの最初のニュースのURLを表示
session.visit('http://www.yahoo.co.jp')
first_news = session.find('.emphasis li:nth-child(1) a')
puts first_news.text
puts first_news[:href]

# スクリーンショット取得
session.save_screenshot('screenshot.png')

ちなみにunstableの頃は--disable-gpuオプションが必要でしたがstableでは不要でした。
実行結果は下記のようになりました。

$ bundle exec ruby example.rb
東芝9500億円の赤字 暫定発表NEW
https://rdsig.yahoo.co.jp/_ylt=A2RiysB8LBlZ1i0AiOWJBtF7/RV=2/RE=1494908412/RH=cmRzaWcueWFob28uY28uanA-/RB=/RU=aHR0cHM6Ly9uZXdzLnlhaG9vLmNvLmpwL3BpY2t1cC82MjM5ODA3AA--/RK=0/RS=A7xNNjt06BRv_BBkvEZQesO0gCg-
screenshot-tofu

Oh… tofu…
ということで、DOM操作はできてるのですが日本語フォントが無いため豆腐になっています。切ないですね。
なので日本語フォントも追加します。今回はnotoを使います。

$ wget https://noto-website-2.storage.googleapis.com/pkgs/NotoSansCJKjp-hinted.zip
$ mkdir /usr/share/fonts/noto
$ unzip NotoSansCJKjp-hinted.zip NotoSansCJKjp-Regular.otf NotoSansCJKjp-Bold.otf -d /usr/share/fonts/noto/
$ fc-cache -v

そして再度Selenium Standalone Serverを起動し、example.rbを実行してみたところ…

screenshot

うまくいきました!テスト等で活用できること間違いなしですね…!

さいごに

実はこれまでもselenium/standalone-chrome等、
xvfbを使用することで非デスクトップ環境でも各種ブラウザを使用する術はありました。

ですが、ブラウザがネイティブでヘッドレスになったことで、オーバーヘッドもイメージ容量も削減することができるため、
リソース的なメリットがでてきます。selenium/standalone-chromeと比べて容量削減できました!わーい!

こちらからは以上です。

おまけ

Docker Imageでくれ

どうぞ!

docker pull jinguji/selenium-standalone-chrome-jp

Dockerfileでくれ

ここにあります!