読者です 読者をやめる 読者になる 読者になる

ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

WebDriver について私が知っていること (2017 年版)

もともと Selenium 2.0 で導入された WebDriver ですが、単に 「WebDriver」 と言ってもいろいろなものを指すことがあり *1、WebDriver を初めて使おうとする人にはややこしい状況だと感じています。 (私は数か月前に WebDriver を使おうとして混乱しました。)

というわけなので、私が調べた 「WebDriver とは何か」 を簡単にまとめておきます。

WebDriver とは何か

WebDriver とは、ユーザーエージェント (web ブラウザ) を外部のソフトウェアから操作したり情報を取得したりできるようにするためのものです。 テストの自動実行などに便利ですね。

W3C WebDriver と Selenium WebDriver

冒頭で述べた通り、Selenium 2.0 の目玉機能として導入された WebDriver なのですが、現在は W3C が発行する WebDriver 勧告も存在します。 W3C WebDriver は Selenium WebDriver をもとに策定されていて、概念的には基本的には同じなのですが、言葉の定義が違っていてややこしいので分けて説明します。


W3C WebDriver
  • ドキュメント : WebDriver (W3C)
  • ユーザーエージェントの内部状態の取得や操作を可能にする遠隔操作のためのインターフェイス
  • HTTP 準拠の wire プロトコル となっている。
  • WebDriver のクライアント側を Local End といい、ユーザーエージェント側を Remote End という。
    • Remote End は 2 種類のノードに分けられて、他の Remote End のノードのプロキシとして働く Intermediary node と、ユーザーエージェント (または類似のプログラム) によって提供される Endpoint node がある。 ( https://w3c.github.io/webdriver/webdriver-spec.html#nodes )
  • WebDriver 仕様では、リモートエンドがどのように振る舞うべきかも書かれている。
Selemium WebDriver

各種 Driver 実装

初期には Selenium が独自に Driver を実装していたようなのですが、現在では各ブラウザベンダーがそれぞれ Driver を実装しているという状況です。

仕様と実装について

W3C WebDriver の仕様は最近もいろいろ変化していて、Driver 実装と W3C WebDriver のドキュメントがしばしば異なっていることがあります。 Obsolete ではあるのですが、SeleniumJSON wire protocol のドキュメントの方が実際の Driver の実装にあっていることもあるので、そちらもあわせて参考にするといいでしょう。

また、WebDriverIO の API ドキュメント も参考になります。 各コマンドのドキュメントページに 「View Source」 のリンクがあるので、どういう実装になっているのか見てみるといいでしょう。

とりあえず使ってみる (スクリーンショットを撮る例)

とりあえず WebDriver を使ってみるには、ブラウザとその Driver、それから HTTP を発行できるコマンドさえ使えれば大丈夫です。

ここでは WebDriver API (HTTP プロトコル) を使い、Firefox でスクショを撮ってみましょう。

Driver (geckodriver) の準備

Firefox のバイナリは既に存在するとします。 Firefox 用の Driver である geckodriver は GitHub 上でリリースされていますので、ダウンロードしてきます。

下記のようなコマンドで geckodriver を起動します。 (Linux での例です。 各自環境に合わせていい感じに実行してください。)

# geckodriver 起動
/opt/geckodriver/geckodriver --host 0.0.0.0 --port 9516 --binary /usr/bin/firefox

WebDriver コマンドの発行

あとは WebDriver のコマンドを発行していくだけです。 以下は PowerShell の例ですが、各自環境でいい感じに HTTP リクエストを発行してください。

# セッション開始 (レスポンス中の sessionId の値を後続のコマンドで使用する)
$session = Invoke-RestMethod -Method POST -Uri http://localhost:9516/session -Body $(ConvertTo-Json(@{}))

# ページ遷移
Invoke-RestMethod -Method POST -Uri http://localhost:9516/session/$([System.Web.HttpUtility]::UrlEncode($session.value.sessionId))/url -Body $(ConvertTo-Json(@{ url = "http://vividcode.hatenablog.com/" }))

# スクリーンショット取得
$screenshot = Invoke-RestMethod -Method GET -Uri http://localhost:9516/session/$([System.Web.HttpUtility]::UrlEncode($session.value.sessionId))/screenshot

# Base64 デコードしてファイルに出力
[System.IO.File]::WriteAllBytes($(Join-Path $(Convert-Path .) test.png), $([System.Convert]::FromBase64String($screenshot.value)))

# セッション終了
Invoke-RestMethod -Method DELETE -Uri http://localhost:9516/session/$([System.Web.HttpUtility]::UrlEncode($session.value.sessionId))

スクリーンショット{"value":"xxxx"} のような JSON で返ってきます。 value の値は Base64 エンコードされた画像の値なので、Base64 でデコードしてやってファイルに書き出すとスクリーンショットを見ることができます。 上の例ではコマンドで変換してファイル出力しちゃってますが、コマンドでの変換が難しい環境の場合は、http://www.convertstring.com/ja/EncodeDecode/Base64Decode のような web 上の Base64 デコーダを使ってデコードするのが楽でしょう。

今回の例では、以下のような感じでスクショを撮ることができました。

f:id:nobuoka:20170507214630p:plain

Remote End を Docker 環境で用意する

自動テストで使用する場合など、ブラウザ自体や Driver を含んだ環境を手軽に用意できると便利ですよね。

FirefoxChrome については、wakaba さんが公開している Docker イメージがあります。

Docker 環境さえあれば docker run -it --rm -p 9516:9516 -t quay.io/wakaba/firefoxdriver:stable という感じで Firefox と geckodriver の環境を手に入れられるので便利です。 これらのイメージは Selenium に依存していません。

Selenium が公開している Docker イメージもあります。

こちらは Selenium Server が入っているので、Selenium Server 経由で使いたい場合はこちらを使うといいでしょう。

*1:クライアントライブラリだったり Driver だったりプロトコルだったり