selenium gridやjenkinsを返さず単体のコードのみで複数のdriverを並列実行
複数のdriverを一気に立ち上げる
複数のdriverを宣言するのには普通に考えると以下のようになります。
1 2 3 4 5 6 7 8 9 10 |
driver1 = Selenium::WebDriver.for :chrome driver2 = Selenium::WebDriver.for :chrome driver3 = Selenium::WebDriver.for :chrome driver4 = Selenium::WebDriver.for :chrome driver5 = Selenium::WebDriver.for :chrome driver6 = Selenium::WebDriver.for :chrome driver7 = Selenium::WebDriver.for :chrome driver8 = Selenium::WebDriver.for :chrome driver9 = Selenium::WebDriver.for :chrome driver10 = Selenium::WebDriver.for :chrome |
スマートじゃないですよね。。。
for文とかでできないかなと思うのですが。。こんな感じで。
1 2 3 4 5 6 |
for i in 1..10 do "driver#{i}" = Selenium::WebDriver.for :chrome end => syntax error, unexpected '=', expecting keyword_end "driver#{i}" = Selenium::WebDriver.for :chrome |
syntax errorですね。。。
配列でいける
配列でやってみましょう。
1 2 3 4 |
driver = [] (1..10).each do |n| driver[n] = Selenium::WebDriver.for :chrome end |
10個のドライバーが立ち上がりましたね。
同じように以下でもいけます。
1 2 3 4 |
driver = [] 10.times do |n| driver[n] = Selenium::WebDriver.for :chrome end |
これでdriver配列に10個のselenium webdriverオブジェクトが入りました。
それぞれのdriverの呼び出しはdriver配列の中を呼び出すので
1 2 3 |
driver[0].get("http://google.com") driver[1].get("http://google.com") driver[2].get("http://google.com") |
で大丈夫です。
seleniumの並列処理
例えば、以下のようなコードを実装した時に
1 2 3 |
driver[0].find_element(:id, "element").click driver[1].find_element(:id, "element").click driver[2].find_element(:id, "element").click |
driver[0]のクリックで画面がロードが終わってからdriver[1]の処理が始まります。
これを全てのドライバーで一気にクリックを行いたいと思いました。
seleniumの並列処理と言えば、selenium gridやjenkinsというイメージがありますが、
同一の処理を複数のドライバーで行うのであれば単体のコードのみで実装できます。
threadクラスを使う
同一の処理を複数のドライバーで行いたい時に Parallel でやってみたのですが、
seleniumとの相性が悪いのかうまく動きませんでした。
そこで特別なgemなどを使わずに標準で入っているthreadクラスで試してみました。
1 2 3 4 5 6 7 |
threads = [] driver.each do |d| threads << Thread.new do d.find_element(:id, 'element').click end end threads.each { |t| t.join } |
おおお、すべて並列で動作していますね。
threadクラスに関してはドキメントがあるので見てみてください。
class Thread (Ruby 2.4.0)
まとめ
では、複数のdriverを立ち上げてそれを並列処理するためのコードをまとめてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
require 'selenium-webdriver' driver = [] (1..10).each do |n| driver[n] = Selenium::WebDriver.for :chrome end threads = [] driver.each do |d| threads << Thread.new do d.get("http://google.com") end end threads.each { |t| t.join } |
スマートに複数driverでの並列実行ができましたね。