それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

watir をぱぱっと使うための、使い方まとめ。

できればMechanizeで動かしたいけど、Watirでブラウザのオートパイロットが楽だしねぇ。

なんでWatirなの?

Q:Watir骨董品じゃん?Capybara-webkitで良いんじゃない?
  • A1: Capybara 機能多すぎてスクレーピングには初期学習コストが高そう。
  • A2: Capybara はテストフレームワークであってオートパイロットシステムでもない、そのため検索してもスクレーパー以外の記事が多い
  • A3: Selenium には wait_until_present? という超便利な関数がない。
  • A4: PhantomJS も自動操縦向きじゃない(PDF取得とか)

というわけで、レガシィな物を持ち出しましたら、意外に使えrfdsふぁsd(っていうか中身Seleniumだし)

すいません、嘘です。OSXでCapybaraインストールにコケたので一昨年からWatir使ってました。

インストール

gem install watir watir-webdriver

WindowsならWin32OLEで更に遊べる。

初回起動

require "watir"
require "watir-webdriver"
profile = Selenium::WebDriver::Firefox::Profile.new
browser = Watir::Browser.new :firefox, :profile => profile
browser.goto "https://id.auone.jp/"

Headless(xvfb)経由で起動

X Virtual Framebuffer の仮想X11 ( DISPLAY:99 ) で起動する xvfb は X11 の vfb のこと。vfb は virtual frame bufferのこと。

require 'headless'
require "watir"
require "watir-webdriver"
Headless.new
headless.start
profile = Selenium::WebDriver::Firefox::Profile.new
b = Watir::Browser.new :firefox, :profile => profile
headless.destroy

自動処理の時はブラウザ画面を起動せない。

Windows/mac OS X では、そのままではxvfb-run は使えない。Xvfbを動かすにはx11が必要。

IEWin32 OLEで使うのなら IE を非表示できるが、OSXSafariだとどうやるかはちょっとわからないです。

ブラウザのバージョンを調べる

b.driver.capabilities

もしくは、exec_script を通してwindow.navigator.userAgentを実行しUAなどを見る

watirXPATH

browser.element( xpath: "//a[contains(.,'ポイント利用状況')]" ).click

watirCSSセレクタ

browser.element( css: "input[type='password']" )

watir でJS実行

browser.execute_script("document.querySelector('div#side').remove()")

watir で表示中のHTML取得

browser.html

watir で要素のHTMLの取得

browser.(css:"#sample").html

watir で特定属性にアクセス

browser.a(:css => "div.foo").html
browser.a(:css => "div.foo").href
browser.a(:css => "div.foo").text

特定のタグとCSSセレクタの組合せ

browser.h1( css: ".header" )
browser.a(:css => "div.foo")

特定のタグとXpathの組合せ

browser.h1( xpath: "./a[contains...]" )

正規表現で要素を絞る

browser.a( html: /login/ )
browser.a( text: /ログイン/ )

JSで要素へ命令文

browser.execute_script("document.querySelector('a#side').click()")

フォームに値を仕込む

browser.element( css: "input[type='password']" ).set "mypassword"

基本設計としてリードメインで作られているらしいWatirなので、#set 経由でないと値を送れない。

キーボードイベントが発生しないので特定のフォームでは動かない可能性

JSを使っても出来る

browser.execute_script(
"document.querySelector('input[type=password]').value='%s'" % password
 )

ページの更新reload

browser.refresh

もちろんjsでも出来る。

要素の属性値の書換

js でしか出来ない

browser.a( href: /dpoint/).target="" # 出来ない

Javascriptでやる。

  ret = document.evaluate("(//a[contains(@href,'dpoint')])[1]",document,null,XPathResult.ANY_TYPE,null);
  a = ret.iterateNext();
  a.target=''

面倒だけど他に方法がない。

Ajax メインのページのロード待ち

JSライブラリで出来たページは、 browser.waitでは検出できない

特定の要素が現れるまで待つ。

browser.div(css:"#active_content").wait_until_present

逆に、特定の要素が消えるまで待つ。

browser.div(css:"#deActive_content").wait_while_present

これで待つしか無いようだ。

exec_scriptのjsを通してブラウザの状態を取得することもできるが、特定の要素の出現を待つほうが確実でした。

特定の要素を消す。

remove系は存在しない。DOM操作はJSから作業する

browser.execute_script("document.querySelector('#{selector}').remove();")

要素があるかないか

未ログインやログイン済、ロード済の判定など、指定の要素がDOMに存在スルか調べるとき

if my.browser.img(alt:/未認証/).present? then
 do_something
end

要素の存在・表示・可視のチェック3種

exits?は、ほとんど使うことがないとおもう。

Element .exists? .present? .visible?
Displayed (browser.div(:id => 1)) true true true
Not Displayed (browser.div(:id => 2)) true false false
Non-Existent (browser.div(:id => 3)) false false exception

wait / wait{while,until}present の違い

  • wait は、document.readyState == 'complete' or timeout 5 sec が発火条件
  • wait{while,until}presentは、Elementsが表示されるのが発火条件

wait よりもwait{while,until}present を使うほうが無難なことが多い。

元のウインドウに戻して!

いまどき別ウインドウをあげちゃうようなサイトがあるので、もとのウインドウに戻して

browser.windows[n].use  

ウインドウをアクティブにして

browser.activate

watir 起動が面倒くさい

rake irb を使って自動処理しておく

takuya@~:$ rake irb
>> init
>> browser 
>> browser.goto "http://au.kddi.com"
Rakefile
task :pry do
  require 'pry'
  $LOAD_PATH  << "./lib"
  def init; 
     # 初期化処理
     require 'headless'
     require "watir"
     require "watir-webdriver"
     # よく使う関数とか
  end
  binding.pry
end
irb ならこんな感じ
task :irb do
  ARGV.clear
  IRB.conf[:SAVE_HISTORY] = 100000
  IRB.conf[:PROMPT_MODE] = :SIMPLE
  IRB.conf[:AUTO_INDENT] = true
  IRB.start
end

困ったときのDocument

watir-webdriverを見ると何となくわかってくる。

それでも困ったら

Selenium Driverを使う限りSeleniumのドキュメント見たほうが速いです。

https://github.com/SeleniumHQ/selenium/wiki/Ruby-Bindings

参考資料

http://stackoverflow.com/questions/9296353/running-javascript-in-watir-webdriver

http://stackoverflow.com/questions/9302737/ruby-watir-to-get-html-of-a-page

http://stackoverflow.com/questions/9006223/watirexceptionmissingwayoffindingobjectexception-invalid-attribute-css

http://stackoverflow.com/questions/12531705/how-to-get-element-with-css-in-pageobject

http://grokbase.com/t/gg/watir-general/144adwpzh3/wtr-general-need-info-about-how-to-get-browser-version-in-watir-classic-and-about-ie8-and-ie9-support

https://jkotests.wordpress.com/2012/11/02/checking-for-an-element-exists-visible-present/