こんにちは。学生エンジニアの橋本です。今回は、seleniumでクローラーを開発する際に便利なexecute_scriptメソッドの解説をします。このメソッドはJavaScriptをwebページに対して実行してくれるものです。

execute_scriptを使わない場合

クローラーを作る際、webページ特定のボタンをクリックしたり、フォームに書き込む処理が必要になります。そんな場合、seleniumではfind_elementメソッドで要素を指定してclickやsend_keysメソッドを使うことで処理することができます。 例として、弊社のホームページにアクセスし、「CONTACT」をクリックし、会社名、担当者名、電話番号を埋め、送信ボタンを押すという動作をseleniumで実装してみます。
require 'selenium-webdriver'

Selenium::WebDriver::Chrome.driver_path = "/mnt/c/chromedriver.exe"
ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.102 Safari/537.36'
caps = Selenium::WebDriver::Remote::Capabilities.chrome('chromeOptions' => { args: ["--user-agent=#{ua}", 'window-size=1280x800', '--incognito'] }) # シークレットモード
client = Selenium::WebDriver::Remote::Http::Default.new
client.read_timeout = 300
@driver = Selenium::WebDriver.for :chrome, desired_capabilities: caps, http_client: client
@driver.manage.timeouts.implicit_wait = 30

@driver.navigate.to'https://rooter.jp/'
@driver.find_element(:class,'btn').click
@driver.find_element(:name,'company-name').send_keys("rooter")
@driver.find_element(:name,'your-name').send_keys("ルータロウ")
@driver.find_element(:name,'tel-number').send_keys("09012345678")
@driver.find_element(:class,'wpcf7-submit').click

このコードを実行すると次のような画面になり意図した通りにページを動かすことができています。 この場合はJavaScriptを使わなくても実装はできますが、これを開発する際、正確に要素を指定できているかを確認するのに毎回rubyを実行しなければなりません。また、find_elementでの指定の仕方に制限があったり(valueやalt属性での検索ができない等)、ページによってはスクロールできないページで要素が画面外にあったりするとうまく動作を実装できないことがあります。

execute_scriptを使った開発

まずは先ほどの動作をexecute_scriptで実装した場合のコードをお見せします。(seleniumの設定部分は割愛)
@driver.navigate.to'https://rooter.jp/'
@driver.execute_script(%Q{document.querySelector("a.btn").click()})
@driver.execute_script(%Q{document.querySelector("[name='company-name']").value = "rooter"})
@driver.execute_script(%Q{document.querySelector("[name='your-name']").value = "ルータロウ"})
@driver.execute_script(%Q{document.querySelector("[name='tel-number']").value = "09012345678"})
@driver.execute_script(%Q{document.querySelector("[value='送信']").click()})

execute_scriptの引数に直接実行したいJavaScriptを入れています。これを使うと、webブラウザで実行しながら開発することができます。webブラウザでの実行は、chromeの場合、デベロッパーツールのConsoleタブにJavaScriptを打ち込むだけです。開発時には結局デベロッパーツールを見ながら開発するので、rubyのエディタやターミナルを行き来する回数が減り効率よく開発できるのではないでしょうか。

また、JavaScriptをrubyファイル上に毎回書くのは読みにくくなるので次のように関数としてまとめてやるとすっきりします。この場合、cssセレクタや埋めたい値を指定します。

def query_click(css_selector)
  javascript_statement = %Q{document.querySelector("#{css_selector}").click()}
  @driver.execute_script(javascript_statement)
end

def send_value(css_selector,value)
  javascript_statement = %Q{document.querySelector("#{css_selector}").value = "#{value}"}
  @driver.execute_script(javascript_statement)
end

query_click("a.btn")
send_value("[name='company-name']",'rooter')
send_value("[name='your-name']",'ルータロウ')
send_value("[name='tel-number']",'09012345678')
query_click("[value='送信']")

まとめ

execute_scriptによってseleniumにJavaScriptを実行させるというお話でした。ページによってはクリック時の動作としてソースにそのままJavaScriptが書いてあるものもあるので、そうしたページを動かす時にさらなる威力を発揮するかもしれません。是非活用してみてください。