Webサイトのクローリングや、開発しているWebアプリのUATとして、たとえばSeleniumを使ってブラウザテストを行いたいケースはよくあるでしょう。では、これらをHeroku上で実施するには...?
Heroku CI では、Heroku CI: Browser and User Acceptance Testing (UAT)というベータ機能
を提供しています。ここで、headless Chromeを利用することができるようになっており、この機能を活用することで、UATやクローリングを実装することができます。
Headless Chrome を Heroku 上で利用するには
なんてことはありません https://github.com/heroku/heroku-buildpack-google-chrome
buildpack を入れるだけです。Headless Chromeを操作するために、別途言語のランタイムも必要になるでしょうから、複数の buildpackを指定する multi buildpack
構成になります。偉そうに名前をつけていっていますが、ただ、複数のbuildpackを入れるだけです。
buildpack の入れ方は、Heroku Dashboardからでも、Heroku CLIからでも、カンタンに導入可能です。
Heroku Dashboard からの場合
利用したい Herokuアプリのダッシュボードで、Settings
タブへ移動します。Buildpacks
項目で「Add Buildpack」というボタンがありますので、これをクリックし、追加で利用したいbuildpackのURLまたはプログラミング言語名を入力したあと Save changes
するだけです。
Heroku CLI の場合
heroku buildpacks:add
コマンドを利用します。通常は heroku buildpacks:set
コマンドで、該当のプログラミング言語を指定します。multi buildpacks 構成にするには、buildpacks:add
で追加を行うことになります。くわしくは、Using Multiple Buildpacks for an Appをご覧ください。
heroku buildpacks:add https://github.com/heroku/heroku-buildpack-google-chrome -a <APP_NAME>
<APP_NAME>
には対象の Herokuアプリ名を指定
Selenium も使いたい!!
Selenium を使う場合には、更にheroku-buildpack-chromedriver buildpack が追加で必要になります。追加の方法は Chrome Driver と同じで、更に buildpackを追加します。
追加する Chrome Driver のURLは https://github.com/heroku/heroku-buildpack-chromedriver
となります。
Selenium on Heroku の利用方法
さて、buildpackを設定して、これらを実際に使う場合にはどのようにすればよいでしょうか。次の2点に気をつければ問題ありません。
- Headless Chromeを利用するには
--headless
および--disable-gpu
オプションが必要です - chrome の binary PATH は、環境変数
$GOOGLE_CHROME_SHIM
を指定します
設定サンプル
例えば Ruby
の場合、次のように指定します。
options = Selenium::WebDriver::Chrome::Options.new
options.binary = ENV.fetch(“GOOGLE_CHROME_SHIM”)
options.add_argument('headless')
options.add_argument('disable-gpu')
driver = Selenium::WebDriver.for :chrome, options: options
あとは、普段どおりにSeleniumをしばき倒せば問題ありません。
Heroku CI上で利用する場合には
Heroku CIで、UATとして利用するには、app.json
でbuildpackを利用するよう定義しておく必要があります。
例えば test
環境で定義するには、environments
内に次のようにbuildpacks
を定義しておきます。
{
"environments": {
"test": {
"buildpacks": [
{ "url": "heroku/ruby" },
{ "url": "https://github.com/heroku/heroku-buildpack-google-chrome" },
{ "url": "https://github.com/heroku/heroku-buildpack-chromedriver" }
]
}
}
}
注意事項
- この2つのbuildpackは、公式として提供されているわけではないので、現時点では未サポートです
おまけ - Selenium on Heroku でダウンロードする場合には
ファイルをダウンロードしたいんだと言うときには、次の注意点に留意して実行します。
-
setDownloadBehavior
をallow
設定にする - 指定したディレクトリに自動ダウンロードするように
preference
を設定する
Ruby で設定するには
setDownloadBehavior
をallow
させるには、次のようなメソッドを定義し、Selenium の driver
と、ダウンロード先directory
を明示して、指定したダウンロード先へのダウンロードを許可します。
将来、Google Chrome の内部構造の変更により、この書き方が変更になったり、不要になる場合が想定されます。
def enable_chrome_headless_downloads(driver, directory)
bridge = driver.send(:bridge)
path = '/session/:session_id/chromium/send_command'
path[':session_id'] = bridge.session_id
bridge.http.call(:post, path, {
"cmd" => "Page.setDownloadBehavior",
"params" => {
"behavior" => "allow",
"downloadPath" => directory,
}
})
end
例えば、prefs
というオブジェクト内に、ダウンロードするディレクトリと、自動的にダウンロードするオプションを指定して、options.add_preference
で追加設定を行うように指定します。
prefs = {
prompt_for_download: false,
directory_upgrade: true,
default_directory: download_directory
}
options.add_preference(:download, prefs)
Worker Dyno として利用する場合の注意事項 (2019/5/31追記)
実際に運用されている開発者の方から、Worker Dyno として起動させ続けるようなケースにおいての注意事項をいただきましたので、追記しておきます。対処法など分かれば、また追記します。
- Dyno Restart の際、
SIGTERM
が送られてくると、その時点で Chromeのプロセスが先に停止してしまう様子。すると、Selenium側からの実行で制御不能になるとのこと - One off dyno の場合、24時間以上動作するようなケース以外では、強制停止のみなので、この事象には当たらないものと想定される