我正在使用Watir来测试我的Web应用程序。我使用CSS选择器来访问各种元素。在下面的例子中,我试图从表中读取所有数据。
在第一种方法中,我获取所有表行,然后从行中的每个单元格中读取文本。
在第二种方法中,我正在使用其选择器读取每个单元格。令我感到惊讶的是,第二个比第一个快了大约三倍。
方法1:
rows = $browser.table(:id,"bin_die_count").rows
while index < rows.count
bin_details = {}
speed_grade = rows[index][2].text
die_count = rows[index][3].text
bin_value = rows[index][0].text
bin_details = {"speed_grade" => speed_grade, "die_count" => die_count}
all_bin_details[bin_value] = bin_details
puts bin_details
index = index + 1
end
方法2:
row_count = $browser.table(:id,"bin_die_count").rows.count
while index < rows.count
bin_details = {}
speed_grade = $browser.element(:css,"#bin_die_count > tbody > tr:nth-child(#{index}) > td:nth-child(3)").text
die_count = $browser.element(:css,"#bin_die_count > tbody > tr:nth-child(#{index}) > td:nth-child(4)").text
bin_value = $browser.element(:css,"#bin_die_count > tbody > tr:nth-child(#{index}) > td:nth-child(1)").text
bin_details = {"speed_grade" => speed_grade, "die_count" => die_count}
all_bin_details[bin_value] = bin_details
puts bin_details
index = index + 1
end
此处方法1完成46.555秒,方法2耗时16.025秒。 我期望方法1更快,因为它引用相对于行的文本,但方法2引用具有绝对CSS选择器的每个文本。
为什么会这样?
答案 0 :(得分:4)
<强>问题强>
决定性能的最大因素是有线电话的数量 - 即Watir要求Selenium与浏览器通话的次数。
在我简化为rows[0][0].text
的第一种方法中,您会看到以下8个电话:
2017-07-31 11:45:37 INFO Selenium -> POST session/a248a69dfd9ae930072e4a3dbe5a979f/elements
2017-07-31 11:45:37 INFO Selenium >>> http://127.0.0.1:9515/session/a248a69dfd9ae930072e4a3dbe5a979f/elements | {"using":"tag name","value":"tr"}
2017-07-31 11:45:37 INFO Selenium <- {"sessionId":"a248a69dfd9ae930072e4a3dbe5a979f","status":0,"value":[{"ELEMENT":"0.9824074557261091-1"},{"ELEMENT":"0.9824074557261091-2"}]}
2017-07-31 11:45:37 INFO Selenium -> GET session/a248a69dfd9ae930072e4a3dbe5a979f/element/0.9824074557261091-1/enabled
2017-07-31 11:45:37 INFO Selenium <- {"sessionId":"a248a69dfd9ae930072e4a3dbe5a979f","status":0,"value":true}
2017-07-31 11:45:37 INFO Selenium -> POST session/a248a69dfd9ae930072e4a3dbe5a979f/element/0.9824074557261091-1/elements
2017-07-31 11:45:37 INFO Selenium >>> http://127.0.0.1:9515/session/a248a69dfd9ae930072e4a3dbe5a979f/element/0.9824074557261091-1/elements | {"using":"xpath","value":"./th | ./td"}
2017-07-31 11:45:37 INFO Selenium <- {"sessionId":"a248a69dfd9ae930072e4a3dbe5a979f","status":0,"value":[{"ELEMENT":"0.9824074557261091-3"},{"ELEMENT":"0.9824074557261091-4"},{"ELEMENT":"0.9824074557261091-5"},{"ELEMENT":"0.9824074557261091-6"}]}
2017-07-31 11:45:37 INFO Selenium -> GET session/a248a69dfd9ae930072e4a3dbe5a979f/element/0.9824074557261091-3/name
2017-07-31 11:45:37 INFO Selenium <- {"sessionId":"a248a69dfd9ae930072e4a3dbe5a979f","status":0,"value":"td"}
2017-07-31 11:45:37 INFO Selenium -> GET session/a248a69dfd9ae930072e4a3dbe5a979f/element/0.9824074557261091-4/name
2017-07-31 11:45:37 INFO Selenium <- {"sessionId":"a248a69dfd9ae930072e4a3dbe5a979f","status":0,"value":"td"}
2017-07-31 11:45:37 INFO Selenium -> GET session/a248a69dfd9ae930072e4a3dbe5a979f/element/0.9824074557261091-5/name
2017-07-31 11:45:37 INFO Selenium <- {"sessionId":"a248a69dfd9ae930072e4a3dbe5a979f","status":0,"value":"td"}
2017-07-31 11:45:37 INFO Selenium -> GET session/a248a69dfd9ae930072e4a3dbe5a979f/element/0.9824074557261091-6/name
2017-07-31 11:45:37 INFO Selenium <- {"sessionId":"a248a69dfd9ae930072e4a3dbe5a979f","status":0,"value":"td"}
2017-07-31 11:45:37 INFO Selenium -> GET session/a248a69dfd9ae930072e4a3dbe5a979f/element/0.9824074557261091-3/text
2017-07-31 11:45:37 INFO Selenium <- {"sessionId":"a248a69dfd9ae930072e4a3dbe5a979f","status":0,"value":"Product"}
相比之下,第二种方法又简化为browser.td(:css,"#bin_die_count > tbody > tr:nth-child(1) > td:nth-child(1)").text
,只有3个电话:
2017-07-31 11:46:33 INFO Selenium -> POST session/f19ba6fd8cf948b590b36f3c77191624/element
2017-07-31 11:46:33 INFO Selenium >>> http://127.0.0.1:9515/session/f19ba6fd8cf948b590b36f3c77191624/element | {"using":"css selector","value":"#bin_die_count > tbody > tr:nth-child(1) > td:nth-child(1)"}
2017-07-31 11:46:33 INFO Selenium <- {"sessionId":"f19ba6fd8cf948b590b36f3c77191624","status":0,"value":{"ELEMENT":"0.8228824382277831-1"}}
2017-07-31 11:46:33 INFO Selenium -> GET session/f19ba6fd8cf948b590b36f3c77191624/element/0.8228824382277831-1/name
2017-07-31 11:46:33 INFO Selenium <- {"sessionId":"f19ba6fd8cf948b590b36f3c77191624","status":0,"value":"td"}
2017-07-31 11:46:33 INFO Selenium -> GET session/f19ba6fd8cf948b590b36f3c77191624/element/0.8228824382277831-1/text
2017-07-31 11:46:33 INFO Selenium <- {"sessionId":"f19ba6fd8cf948b590b36f3c77191624","status":0,"value":"Product"}
第二种方法只有不到一半的有线电话,这导致大约一半的时间执行。
看起来第一种方法需要更长时间的主要原因是,在获取td
元素的集合时,每个td
元素标记名称都会被验证。例如,一个包含3个td
元素的行将对该名称进行3次调用,具有4个td
元素的行将对该名称进行4次调用,等等。相反,第二种方法只是需要抓取一个特定的td
元素。表格越大,第二种方法节省的时间就越多。
解决方案 - 使用连续的几个单元格
如果您只是挑选一行的几个单元格,则可以通过在没有收集调用的情况下找到特定的td
来避免使用CSS选择器:
rows[0].td(index: 0).text
这提供了与CSS选择器类似的性能。以下表现可以获得单个td
的文本,其中包含25个td
元素:
rows = browser.trs
puts Benchmark.measure { 100.times { rows[0][0].text } }
#=> 45.781881
puts Benchmark.measure { 100.times { browser.td(:css,"#bin_die_count > tbody > tr:nth-child(1) > td:nth-child(1)").text } }
#=> 4.832999
rows = browser.trs
puts Benchmark.measure { 100.times { rows[0].td(index: 0).text } }
#=> 4.812138
解决方案 - 使用连续多个单元格
如果您使用该行的许多td
元素,则最好获取元素集合。但是,您应该为行执行一次,而不是每个单元格执行一次。例如:
row_tds = rows[index].tds
speed_grade = row_tds[2].text
die_count = row_tds[3].text
bin_value = row_tds[0].text
正如您在下面的效果结果中所看到的,一次获取整个集合比单独访问每个单元格更快:
rows = browser.trs
puts Benchmark.measure { 20.times { (1..24).map { |i| rows[0].td(index: i).text } } }
#=> 18.776798
rows = browser.trs
puts Benchmark.measure { 20.times { tds = rows[0].tds; tds.map(&:text) } }
#=> 13.478259
答案 1 :(得分:0)
rows
是一种方法。将其结果分配给变量,您将无法获得尽可能多的有线电话。您还可以通过执行以下操作查看基础请求:Selenium:WebDriver.logger.level = :info