
ブラウザ操作の自動化: Selenium と Ruby でも書いたが、 selenium が便利すぎて、最近よくスクリプトを書くようになった。
以下のようなノウハウが溜まってきたので、ここらで放出する。
- ウィンドウサイズのリサイズ
- ウィンドウ位置の移動
- スクリーンショットの取得
- 要素セレクタメソッドの使い分け
- ドロップダウンリストの選択
- マウスオーバ (hover)
- フレーム移動
- ポップアップダイアログの扱い
- コード量を減らすためのモンキーパッチ
- よく採るプログラム構造
インストール方法などは ブラウザ操作の自動化: Selenium と Ruby を参照。
selenium用スクリプト開発のノウハウというべきかコツといういべきかアレな感じだが、結局、 スクレイピングと同様にHTML構造を理解することが必要なのでブラウザ付属の開発ツールが 手離せない。
これ以降のサンプルコードは以下を定義しているものとする。
1 2 3 | |
ウィンドウサイズのリサイズ
driver.manage.window.resize_toの引数にリサイズするサイズ情報(width, height)を渡す。
1 2 3 | |
現在のサイズを取得して、相対的にリサイズしたい場合は以下のようにする。
1 2 3 4 | |
ウィンドウ位置の移動
driver.manage.window.move_toの引数に移動したい場所の座標情報(x, y)を渡す。
1 2 3 | |
現在のウィンドウ位置を取得して、相対的にリサイズしたい場合は以下のようにする。
1 2 3 4 | |
スクリーンショットの取得
開いているページのスクリーンショットを撮りたい場合は、driver.save_screenshot に保存先のファイル名を指定するだけ。
1 2 | |
ページ全体を撮りたいのに、frame 構造が邪魔をして、スクロールしなければ全体が撮れない場合がある。
ちょっと、調べたところ driver.execute_script("some script") で javascript を利用してスクロールをしている人がいたり、
Selenium::WebDriver::Element.location_once_scrolled_into_view を使ってスクロールしている人がいたり。
どちらにしても、コンテンツ表示上の高さを取得して、1スクロール分の長さをデクリメントしていっているような処理。
自分の場合は、めんどくさかったので、上述したリサイズ方法を使ってスクロールがいらないくらいウィンドウサイズを大きくして、 スクリーンショットを撮るという荒業を繰り広げている。
要素セレクタメソッドの使い分け
要素セレクタメソッドは find_element と find_elements の2種類。
そのメソッド名の単数形・複数形の通りなのだが、以下のような違いがある
find_element- 指定した引数にマッチする最初の要素 (
WebDriver::Element) を 1つ 返す。 - マッチする要素がなければ例外 (
NoSuchElementError) を投げる。
- 指定した引数にマッチする最初の要素 (
find_elements- 指定した引数にマッチする要素を詰めた配列 (
Array<WebDriver::Element>) を返す。 - マッチする要素がなければ、空の配列 (
Array) を返す。
- 指定した引数にマッチする要素を詰めた配列 (
テーブルの <tr> 要素やリストの <li> 要素に対してイテレーション処理するときには find_elements が便利。
以下は、例。
1 2 3 4 5 6 | |
要素セレクタメソッドの引数には、find_element(:how, "what") のように symbol と文字列を渡す。
渡す引数は、find_elements も同じ。
指定できるsymbolの種類は以下。
| symbol | 対象 |
|---|---|
| :class | クラス名 (属性名 class) |
| :class_name | 上記 :class と同じ |
| :id | ID (属性名 id) |
| :link_text | <a> タグのテキスト |
| :link | 上記 :link_text と同じ |
| :partial_link_text | <a> タグのテキストの部分文字列 |
| :name | name (属性名 name) |
| :tag_name | タグ名 |
| :xpath | xpath で指定 |
| :css | css セレクタ で指定 |
参考 Module: Selenium::WebDriver::Find
ドロップダウンリストの選択
Selenium IDEでRubyコードの出力をしようとすると、ドロップダウンリストの選択をする処理部分がERRORに なってコメントアウトされることがある。(今のSelenium IDEバージョンでは大丈夫そう)
ドロップダウンリストの選択は以下のように書けばOK。
1 2 3 4 | |
マウスオーバ (hover)
例えば、ナビゲーションメニューなどが、通常時には折りたたまれていて、メニュー上にマウスオーバした場合に、 子メニューが展開されるようなページがある。 折りたたまれているときに、子メニューHTMLをロードできていないようなページのときは、ユーザ操作と同じように マウスオーバしてあげる必要がある。
以下のようにマウスオーバしたい要素を指定して、driver.mouse.move_to を呼べば良い。
1 2 | |
フレーム移動
frame や iframe 要素を使っているサイトで、そのフレーム内の要素に対して操作したい場合、当該フレームへ切り替える操作が必要となる。
以下のようにスイッチしたいフレーム要素を指定して、driver.switch_to.frame を呼べば良い。
1 2 | |
フレームを移動してから、いったん最上位のフレームにに戻りたい場合は、以下。
1 2 3 4 | |
ポップアップダイアログの扱い
「マジでこのページから移動する?」的なjavascriptによるポップアップダイアログを表示するページがある。 このポップアップダイアログを強制的に閉じるには以下のようにする。
.accept ではい、.dismissでいいえを押して閉じる。
1 2 3 4 5 6 7 | |
コード量を減らすためのモンキーパッチ
たとえば、ログインなどの処理の際、フォームへ文字列を送る send_keys 前にいつも .clear しているので
もう send_keys の中に .clear 処理を入れ込んでしまえと思った。
また、input タグの値を取得するときは、.attribute("value") と長ったらしく書く必要があるので .valueメソッドを
定義してしまおうと思った。checkbox のチェック有無も同じく。
そこで、Selenium::WebDriver::Element を拡張するため、以下のようなモンキーパッチを書く。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | |
そうすると以下のようにコード量を減らせる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
モンキーパッチの書き方は以下を参考にした。
よく採るプログラム構造
よく採るプログラム構造は以下。
- 操作ターゲットとなるサイト単位にクラスを作る
- 処理の内容にしたがって、メソッドを作る。以下の様な粒度。
- サインイン
- リスト表示
- 自動入力と申請
- アカウント情報や入力データはYAMLファイルなどに書き出しておく
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |