Seleniumの操作
2016/7/26 ここで説明しているモジュールをtrail_seleniumという名前でgem化しました。
gem install trail_seleniumで利用できます。
Seleniumを使用してWebブラウザ(Firefox)を操作する方法を紹介します。 一般的にはWebサイトのテスト用として紹介されることが多いと思いますが ここではSeleniumを使用してWeb上のデータを収集したり操作したりする事に視点を置いて 作成したTrail_Seleniumを通して紹介します。
Rubyについては知っているものとします。
Seleniumを使用するには ruby ver 2.0 以上 を使用してください。
Trail_Seleniumの関数の詳細仕様はドキュメントを参照してください。
Trail_Seleniumドキュメント
Trail_Selenium
Seleniumをラップして、Web上の画像や文字列を 簡単にExcelに取り込めるTrail_Seleniumクラスを 作成しました。
Seleniumの機能はそのまま使えます。ページ内の要素の指定で例外が出る場合への対応と 画像の保存、保存した画像のExcelへの貼り付け、データのコンソール出力とExcel出力、 セレクトボックスの指定、等を拡張しています。
Excelへの出力は必須では有りません。open_excelを使わなければExcelへのアクセスは発生しません。
Trail_Seleniumの準備
rubyでSeleniumを使用するには gemでseleniun-windriverをインストールするだけです。 SeleniumwでFirefoxで以外も操作したい場合の詳細なインストール方法は別サイトを検索して下さい。
gem install selenium-webdriver
実行時にunable to get stable firefox connection とエラーに成ることがあります。、 この時はFirefoxを最新にアップデートし、かつseleniumのgemも最新にして下さい。
gem update selenium-webdriver
Trail_Seleniumクラスは、 rubyで画像ファイルのピクセルサイズを取出すためにfastimageを使用します。 gemでfastimageをインストールして下さい。
gem install fastimage
Trail_Selenium.rbとexcel.rbをプログラムと同じフォルダーに置き あなたのRubyスクリプトにTrail_Seleniumをrequireで取り込んで使用してください。
require './trail_selenium'
Trail_Seleniumは下記に置いてあります。
Trail_Selenium
Excelモジュールも同梱してあります、当サイトの他の場所においてあるExcelモジュールと
内容が多少異なっています。同梱のものを使用してください。
Trail_Selenium.rbの中に例題プログラムもありますので参考にして下さい。 Trail_Selenium.rbを単体で実行するとこの例題プログラムが実行されます。 その場合、同梱のexcel.rb,Report_tenplate.xlsを同じフォルダー内に置いてください。 また、Excelがインストールされている必要があります。
ruby trail_selenium.rb
Trail_Seleniumの起動と終了
Excelを使用しない場合、最小のスクリプトは下記のようになります。 最初の2行は'#'の前に空白等を入れないでください。
#! ruby -EWindows-31J # -*- mode:ruby; coding:Windows-31J -*- require './trail_selenium' ts = Trail_Selenium.new ts.driver.navigate.to( 'サイトのURL') : データ処理 ts.disp_msg_array(offset,['データ1','データ2', ...] ) # 出力 : ts.close
Excelを使用する場合、最小のスクリプトは下記のようになります。
#! ruby -EWindows-31J # -*- mode:ruby; coding:Windows-31J -*- require './trail_selenium' ts = Trail_Selenium.new ts.driver.navigate.to( 'サイトのURL') ts.open_excel('Excelファイルのパス') do |book| sheet = ts.open_report_sheet(book,'シート名') : データ処理 ts.disp_msg_array(offset,['データ1','データ2', ...] ) # 出力 : book.save end ts.close
Trail_Seleniumクラスのインスタンスを作り以後そのインスタンスを操作します。
driverがSeleniumのインスタンスです。これを使えばSeleniumの機能は全て使えます。
下記のようにコピーして使うことも出来ます。
require './trail_selenium' ts = Trail_Selenium.new driver = ts.driver driver.navigate.to( 'サイトのURL')
Webページの要素の取り出し
Firefoxで取り出したい項目の上で右クリックしメニューから「要素を調査」をクリックすると 取り出したい要素の詳細情報を調べることが出来ます。
Webページ内の単一要素の取得にはSeleniumのfind_element、 複数要素の取出しにはfind_elements(sが付いている)を使います。
以下ではTrail_Seleniumのインスタンスとして ts を使用します。
単一要素 e = ts.driver.find_element(:id,'idxxxxx') 複数要素 posts = ts.driver.find_elements(:xpath,'//div[@class="stream"]/ol/li')
要素の指定はidやnameが付いているときにはそれを直接指定して取り出せます。
idやnameは同じものが無いので、その指定だけでピンポイントで要素を指定できますが 取り出したい要素にidやnameが無い場合にはxpathで指定するのが確実です。 xpathの詳細についてはWeb検索してください。
Seleniumの内部文字コードはUTF-8です。日本語を含む文字列の検索が上手くいかない場合、 文字コードを合わせて検索してみてください。
Trail_Seleniumで拡張したfind_element,find_element_untilを使うと見つからない時に nilが返ってきますので、要素の有り無しの判定が楽になります。 Seleniumの同等の関数の場合、見つからない時に例外が発生します。 ただし、Trail_Seleniumで拡張したfind_element,find_element_untilはxpathでの指定のみとなります。
e = ts.find_element('//a[@id="idxxxxx"]') if e 要素があるときの処理 end
複数の要素を取り出した場合、要素の配列として返ってきますので更に個別の要素の処理を行ないます。
posts = ts.driver.find_elements(:xpath,'//div[@class="stream"]/ol/li') #複数要素 posts.each do |post| 個別の処理 end msgs = ts.driver.find_elements(:xpath,'//strong').map{|e| e.text() } #要素の持つ文字列を取り出した配列に変換
取り出した要素から下を更に検索することも出来ます
posts = ts.driver.find_elements(:xpath,'//div[@class="stream"]/ol/li') posts.each do |post| #要素の下を更に検索して取り出す name = post.find_element(:xpath,'.//div[@class="stream-item-header"]/a/strong').text().encode('Windows-31J') end
動的なページの場合、要素が出てくるまで待つ必要が有ります。 10秒まで待つwaitオブジェクトを初期化時に作って有りますので下記のように利用できます。 初期化時に待ち時間(秒)を指定すると変更することが出来ます。 waitはSeleniumのwaitオブジェクトです。
ts = Trail_Selenium(20) # 20秒待つwaitを生成する、指定しない場合10秒 : e = ts.wait.until{ts.driver.find_element(:id,'idxxxxx') }
要素の中のデータ取り出し
要素の中の文字列
取り出した文字列を数値として扱いたいときには to_i等で変換してください。
<p id='id001'>文字列</p> t = ts.driver.find_element(:id,'id001').text() x = t.to_i ## 数値化
要素の中のURL等
取り出した要素をhashとして属性をアクセスすることが出来ます。
<a id='id002' href='xxxxxx'>文字列</a> <img id='id003' src='xxxxxx'> url = ts.driver.find_element(:id,'id002')[:href] url = ts.driver.find_element(:id,'id003')[:src]
要素の中の画像の取り出し
画像が画像ファイルのURLで書かれている場合には直接ファイルとして読み出せますが JavaScript等で動的に生成されている場合には画像の入っている要素を右クリック+Y(画像をコピー)で クリップボードに一旦コピーして画像として保存します。
この2つの方法をTrail_Seleniumに用意してあります。 get_pictureはimgタグのsrcをファイルとして読み取り指定フォルダに保存します。 get_picture_via_clipboardは画像要素を右クリック+Y(画像をコピー)でクリップボードに一旦コピーして指定ファイル名で保存します。 ただし、物によっては右クリックで画像をコピーのメニューが出ないものがありますのでその場合には使えません。
ts.get_picture('','//div[@class="AdaptiveMedia-photoContainer js-adaptive-photo "]/img',:rename=>'Hotaka.jpg') ts.get_picture_via_clipboard(temp_file, './/div[@class="content"]/div[3]//img',:node=>post)
データの出力
Trail_Seleniumには出力用のサポート関数 disp_msg_array が用意して有ります。 オフセットと文字列の配列を渡すとstdoutとExcelに書き込みます。 オフセットは標準出力の場合空白2文字をオフセットで指定した回数出力した後、文字列の配列をカンマ区切りで出力します。 Excelへの出力時はオフセットカラム空けて、次のカラムから配列の値を順に設定します。
ts.disp_msg_array(0,[name,msg])
Excelへの画像の貼り付けはts.add_picture_to_excelを使用してください。 指定したセル位置へ指定したサイズで貼り付けます。fit_x,fit_yをtrueで指定するとカラム幅や行の高さを指定したサイズに合わせます。
ts.add_picture_to_excel(temp_file,ts.report_line_no - 1,3,100,(100*sz[1]/sz[0]), :fit_y=>true)
ブラウザ操作
ページの移動等はボタンやリンクの要素を取り出してclickを実行します。 seleniumで使用できる機能は全て使用できます。
<a id='id002' href='xxxxxx'>文字列</a> ts.driver.find_element(:id,'id002').click
ラジオボタン等も要素を取り出してclickを実行します。
セレクタの選択はts.select_by_textを使用して選択する表示文字列を渡します。 selenium自身の機能を使いたい場合にはts.select_by_textのソースを参考にして下さい。
文字列の入力にはsend_keysを使用します。
ts.driver.find_element(:name, 'Password').send_keys("my_password")
動的なページではクリック対象の要素が無かったり、表示されるまでに時間がかかったりしますので 適宜 待ったり、存在を判定したりしてください。
ブロックを使う ← : Seleniumの操作 :