◆ 目的
モダンでリッチな動的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
◆ クローリングコード
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |