背景
nokogiriやmechanizeでパースしてからxpathを指定で要素を抜き出そうとすると、そのまま動くときと空の配列が返ってくるときがある。
そして、悪いことに目的のサイトでは空の配列が返ってきてしまうパターンだった。
なので色々と調べたところ、目的のサイトでjavascriptが動いているのが良くないらしく、nokogiriとmechanizeでサイトをパースする段階ではjavascript実行前のソースを読み込んでおり、chromeのdevtoolなんかで取得できるxpathは、javascript動作後の動的にhtmlタグが変更された後のものであることが判明。
→存在しないxpathを指定することになるので、空の配列が返ってくるのは期待された動作ということみたい。
p agent.get.bodyを見る限り、欲しい情報はすでに含まれていたので以下の二通りのやり方を検討した。
1.ソースコードから欲しい情報をどうにか指定して抜き出す
2.javascript動かしたあとのhtmlをパースして、chromeなんかで拾えるxpath使う
ざっくり検索かけると、2.のパターンの情報のが多く楽なやり方っぽい。
つまり、seleniumを使うといいらしい。
seleniumで書いたコード
#! ruby -Ku
require 'selenium-webdriver'
driver = Selenium::WebDriver.for :chrome
driver.navigate.to '目的のサイトのログインページ'
id = driver.find_element(:xpath,'//*[@id="login_box"]/form/dl/dd[1]/input')
pass = driver.find_element(:xpath,'//*[@id="login_box"]/form/dl/dd[2]/input')
id.send_keys("自分のID")
pass.send_keys("自分のパスワード")
driver.find_element(:xpath,'//*[@id="mainsubmit"]').click
wait = Selenium::WebDriver::Wait.new(timeout: 3)
driver.navigate.to '目的のページ'
wait = Selenium::WebDriver::Wait.new(timeout: 3)
sinchaku = driver.find_elements(:xpath,'//*[@id="main"]/form/table/tbody/tr[1]/td[2]/a')
sinchaku.each do |i|
puts i.text
end
ほとんど拾い物のコードだけど、javascriptで描画されるサイトで期待通りに動作することを確認できた。
ブラウザで操作する順番で、上からそのまま書いていき、操作したい要素はchromeのdevtoolなんかで見れるxpathで指定していくだけだから簡単。
上記の例だと最後に新着情報の一覧をfind_elementsでとってくるのだけど、そのまま.textメソッドを繋げると配列に対してはundefined methodだと怒られるので、eachで一個づつ要素を取り出して.textメソッドを繋げるとうまくいった。