Edited at

Safari 10 の WebDriver ネイティブサポート

More than 1 year has passed since last update.

こんにちは! みなさんmacOSしてますか!

アップグレード中にフリーズしたせいでリカバリーするのがたいへんだったよ!!! クソが!!!!

なんでわざわざそんなクソなアップグレードを急いでやったかというと、Safariの新バージョンが動く最新の環境で確認したいことがあったからです。AppleによるネイティブサポートのWebDriverです!


Safari 10から、WebDriverがネイティブサポートされることになりました。

これまで、 MacOS Xの標準WebブラウザーであるSafariをWebDriverで自動操作するためには、専用の拡張機能プラグインが利用されていました。

新しくリリースされたSafari 10からは、このプラグインを使わなくても、OS側でWebDriverをサポートしてくれることになりました!

https://developer.apple.com/library/content/releasenotes/General/WhatsNewInSafari/Articles/Safari_10_0.html#//apple_ref/doc/uid/TP40014305-CH11-DontLinkElementID_28

Appleの開発者向けWebサイトには SafariDriverの対応コマンド表 こそ掲載されていますが、現状で最もよくまとまっている公式っぽい導入ドキュメントは WebKitの公式ブログ記事 くらいではないでしょうか。この記事に載っている情報も含め、新しいSafariDriverを具体的にどのように利用できるか確認してみましょう。


新しいSafariDriverやってみよう

新しいSafariをSeleniumで操作するときは、他のブラウザーと同様にSafariDriverサーバーを仲介役として併用することになりました。

Safari 10が導入された環境では、 /usr/bin/safaridriver にSafariDriverサーバーの実行ファイルが置かれています。

$ ls -l /usr/bin/safaridriver

-rwxr-xr-x 1 root wheel 34384 9 14 09:56 /usr/bin/safaridriver

普通は /usr/bin にはPATHが通っていると思いますので、特に環境変数をいじらなくてもすぐに使えるはずですね。

初回起動時だけ、セキュリティーに関する確認ダイアログが表示されます。

ここで実行を許可しておけば、次回からはダイアログは表示されません。

待ち受けポート番号を指定する --port オプションに、既定値を利用する意味の 0 を指定して初回起動を済ませてみましょう。(なお、既定の待ち受けポートは7055/tcpです)

$ /usr/bin/safaridriver --port 0

Could not find the required security authorization right, `safaridriver` will attempt to create it.
Please allow `safaridriver` to make the required changes to the security authorization database.

01.png

さて、これだけではSafariをWebDriverから操作できません。

リモート操作できるAPIがあるということは、セキュリティー上のリスクがあるということです。Safariではセキュリティー上の理由で、WebDriverで動かすことを明示的に許可する設定が必要になります。

環境設定の詳細タブで、チェックボックス「メニューバーに"開発"メニューを表示」にチェックを入れましょう。

02.png

Safariのメニューに「開発」が表示されるようになります。

「リモートオートメーションを許可」を選択して、チェックが入っている状態にしましょう。

03.png

これで、SafariをWebDriverから動かす準備ができました。

先ほど起動したSafariDriverサーバーが開いている7055/tcpにWebDriver APIへのリクエストを投げれば、Safariを自動操作することができます。

自動操作されているSafariは、アドレスバーが黄色になってわかりやすくなっています。

04.png

また、自動操作されているSafariにフォーカスを合わせると、自動操作されていることを示すダイアログが表示され、不用意にユーザー操作されないようになっています。

05.png


公式クライアントライブラリーはバージョン3から対応です。

Selenium の公式クライアントライブラリーでの対応は、最新バージョンの3からです。2系では使えませんしたぶんバックポートもされないので、無駄な抵抗はやめて3系に移行しJava 7も早急に捨てるのだのだのだ(残響音含む)

正確には、Selenium 3.0.0 beta4から新しいSafariDriverに対応しています。ぜひ試してみましょう!

なお、beta3まではバージョン3系で以前のオープンソース版のプラグインを利用するための useLegacyDriver というcapabilitiesが残っていたのですが、beta4では削除されてしまいました。今後、以前のプラグインはもう使えないと考えた方が良いでしょう。


スクリーンショットが一癖あります。


  • SafariDriverサーバーの スクリーンショットを取得するWebDriver API で返ってくるBASE64データが、ChromeDriverサーバーやGeckoDriverサーバーなどと違って、スラッシュ記号がエスケープされた状態になっています。これはJSON仕様としては正しい(エスケープしてもしなくてもいい)実装で、公式クライアントライブラリーもこれに対応して正しくスクリーンショットのデータを取得できる状態になっています。 直接WebDriver APIを叩いていたbash野郎 は気をつけましょう!!!


ベンチマーク

日本Seleniumユーザーコミュニティの提供するサンプルページ上で基本的なAPIを100回実行して、1回あたりの平均値を取得するだけの簡易ベンチマークをやりました。

https://github.com/hiroshitoda/WebDriverBenchmark

実行環境は手元のMacBook Pro実機で、スペックは次の通りです。

CPU
Intel Core i5 2.5GHz

メモリー
16Gbytes

OS
macOS Sierra 10.12

JDK
1.8.0_101-b13

結果は次の通りでした。なかなか軽快に動くのがわかりますね。

ChromeDriver
FirefoxDriver via GeckoDriver
PhantomJSDriver
SafariDriver

WebDriver.get
289ms
249ms
49ms
48ms

WebDriver.findElement(By.Id)
13ms
10ms
10ms
7ms

WebDriver.findElement(By.cssSelector)
11ms
9ms
8ms
5ms

WebElement.clear
64ms
21ms
21ms
9ms

WebElement.sendKeys
70ms
23ms
32ms
66ms

WebElement.click
55ms
23ms
39ms
10ms

TakeScreenshot.getScreenshotAs
119ms
45ms
50ms
24ms