2016年3月24日木曜日

Capybaraを使ってブラウザ操作を自動化


◆ 目的
モダンでリッチな動的WEBインターフェースをコマンド経由で自動操作する。
(WEBに限らず、GUI画面全般を画像認識技術を使いオートメーション化したい場合はこちら)



◆ 対象
試験対象のWEBをIBMのBluemix管理コンソールとした。
https://console.ng.bluemix.net/

個人的に利用することが多く、また定期的に課金情報を把握する必要性があるため、そのチェックを自動化したいと思ったことが動機である。
リッチなインターフェースであるため、このサイトで処理を自動化できれば大抵のサイトでも手順を応用できるだろう。


(乗り越えるべき技術的ポイント)
1. IDとパスワードを使ってログイン

2. 個人設定を表示させるアイコンをクリック
 既存画面の前面へポップアップ画面が表示される
 その管理画面で数か所の項目を選択

3. 課金情報画面へ遷移し、閉じられているサービス単位の課金項目をすべて開示
   (右三角ボタン(▷)を押すと矢印の向きが下(▿)になり課金情報が開く)

1は一般的なフォーム操作である。
難しい部分は2、3だろう。
HTMLが静的ではなく、トリガーイベントにより生成される点である。
ある対象上でマウス操作などをすることでトリガーを発生させ、その動作からできあがったHTMLファイルを操作しなくてはならない。



◆ 利用する道具
言語はRubyを使い、WebのUIテストフレームワークであるCapybaraを利用する。

ブラウザ試験用途の道具としては種々のものがあるがCapybaraを使えば、好みのブラウザをドライバとして指定するだけで共通的な操作で扱うことができる。

・Selenium [ブラウザ利用]
・RackTest [ブラウザシミュレータ]
・Webkit [ブラウザエンジン]
・Poltergeist(PhantomJS) [ブラウザシミュレータ]


またRubyのDSLテストフレームワークとして以下のようなものが有名だろう。
今回は試験用コードは書かないが、テストする場合もCapybaraと親和性高く組み合わせることができる。
・Rspec
・Test::Unit
・MiniTest::Spec
・Cucumber



◆ 事前準備
(Capybaraのインストール)
gem経由で入れる。
$ gem install capybara


(Poltergeist(PhantomJS)のインストール)
先にいくつか試験で使えそうなブラウザを紹介したが、今回はPoltergeist(PhantomJS)を使う。
ブラウザを起動せず(GUIのないヘッドレスブラウザ)、JavaScriptが実行できることからこちらを選んだ。

導入はredhat系OSでは以下の通り。
多少時間がかかる。

$ sudo yum -y install gcc gcc-c++ make flex bison gperf ruby openssl-devel freetype-devel fontconfig-devel libicu-devel sqlite-devel libpng-devel libjpeg-devel

$ cd /usr/local/src/

$ git clone --recurse-submodules git://github.com/ariya/phantomjs.git

$ cd phantomjs

$ ./build.py

$ sudo ln -s /usr/local/src/phantomjs/bin/phantomjs /usr/bin/phantomjs


(nokogiriのインストール)
html解析用にnokogiriも入れておく。
$ gem install nokogiri



◆ クローリングコード
#!/usr/bin/ruby
require 'capybara'
require 'capybara/dsl'
require 'capybara/poltergeist'
require 'nokogiri'
require 'open-uri'
Capybara.configure do |config|
config.run_server = false
config.current_driver = :poltergeist
config.javascript_driver = :poltergeist
config.app_host = "https://console.ng.bluemix.net/"
config.default_max_wait_time = 60
config.ignore_hidden_elements = false
end
Capybara.register_driver :poltergeist do |app|
Capybara::Poltergeist::Driver.new(app, {:timeout=>120, js_errors: false})
end
module Crawler
class Bluemix
include Capybara::DSL
def login(username, password)
page.driver.headers = { "User-Agent" => "Mac Safari" }
visit('')
# <a href="/login" ~>ログイン</a>
click_on "ログイン"
fill_in "username", :with => username
fill_in "password", :with => password
# <a href="#" ~>log in</a>
click_on "log in"
end
def select(region, org)
# 地域と組織の管理画面へ遷移
# 右上顔マークのclickトリガーでajax発生
find("li.profileSetting").trigger('click')
# 地域用画面へ遷移
# 該当の下矢印のclickトリガーでajax発生
find("img.toggle-region-expand").trigger('click')
find_all("p.select-name").each do |name|
if name.text == region
puts "clicked #{name.text}"
name.trigger('click')
end
end
# 組織用画面へ遷移
# 該当の下矢印のclickトリガーでajax発生
find("img.toggle-org-expand").trigger('click')
find_all("p.select-name").each do |name|
if name.text == org
puts "clicked #{name.text}"
name.trigger('click')
end
end
end
def report
# 課金情報を閲覧できるアカウントリンクをクリック
find("a.account-link").trigger('click')
# サービスの右矢印をすべてクリックして情報開示
find_all("span.i-arrow-right-dark-blue").each do |name|
puts "clicked blue #{name.text}"
name.trigger('click')
end
# サービスの配下に出てきたインスタンスの右矢印をすべてクリックして情報開示
find_all("span.i-arrow-right-white").each do |name|
puts "clicked white #{name.text}"
name.trigger('click')
end
# HTMLの描画を待つ
# find系コマンドが続く場合はjquery応答中は描画を待ってくれる
wait_for_ajax
sleep 30
#html = open(Capybara.app_host)
#doc = Nokogiri::HTML.parse(html)
#puts doc
puts doc.xpath("//div[@class='chargesDetailsServicesContainer hideHeaderLabels']")
page.save_screenshot('screenshot.png', :full => true)
end
def wait_for_ajax
sleep 2
Timeout.timeout(Capybara.default_max_wait_time) do
active = page.evaluate_script('jQuery.active')
until active == 0 || active == nil
sleep 1
active = page.evaluate_script('jQuery.active')
end
end
end
end
end
crawler = Crawler::Bluemix.new
crawler.login("ユーザネーム", "パスワード")
crawler.select("米国南部", "組織名")
crawler.report
view raw crawler.rb hosted with ❤ by GitHub