我一直了解到,良好的编码意味着:不要重复自己。但这些天我一直在重复自己,试图让我的scrapers处理超时错误。
对于我单击的每个链接或按钮,我都会添加一个救援异常=>e并刷新页面。
例如
browser.link(:xpath, "//tr[@class='pager'][1]/td/a").when_present.click
变成
begin
browser.link(:xpath, "//tr[@class='pager'][1]/td/a").wait_until_present
browser.link(:xpath, "//tr[@class='pager'][1]/td/a").click
rescue Exception => e
sleep (10)
puts "timed out, let's refresh"
browser.refresh
end
也许有一个更清洁、不重复的解决方案。我试过操纵Watir::等等,但我没能做到。。
class Watir::Wait
alias_method :__do_wait, :wait_until
def wait_until
begin
__do_wait{ yield }
rescue Exception => e
puts "timed out. let's refresh"
$browser.refresh
end
end
end
如果我正确理解您的需求,我认为您希望覆盖WhenPresentDecorator的method_missing
处理。
require 'watir-webdriver'
module Watir
class WhenPresentDecorator
def method_missing(m, *args, &block)
unless @element.respond_to?(m)
raise NoMethodError, "undefined method `#{m}' for #{@element.inspect}:#{@element.class}"
end
begin
Watir::Wait.until(@timeout, @message) { @element.present? }
rescue
sleep(10)
puts "timed out, let's refresh"
@element.browser.refresh
else
@element.__send__(m, *args, &block)
end
end
end # WhenPresentDecorator
end
有了这个猴子补丁,when_present
将等待元素出现。如果元素存在,它将执行操作(即在您的示例中单击)。如果元素不存在,它将捕获异常,忽略它,刷新页面并继续执行下一条语句。
例如,给定以下页面,该页面具有显示页面加载时间的div标记:
<html>
<head>
<script>
function startTime()
{
var today=new Date();
var h=today.getHours();
var m=today.getMinutes();
var s=today.getSeconds();
document.getElementById('txt').innerHTML=h+":"+m+":"+s;
}
</script>
</head>
<body onload="startTime()">
<div id="txt"></div>
</body>
</html>
您可以看到,在访问确实存在的元素(链接)时不会出现异常。此外,在尝试查找该元素后,页面会刷新。
puts browser.div(:id => 'txt').text
#=> "22:48:25"
browser.link(:id => 'asdf').when_present.click
#=> "timed out, let's refresh"
puts browser.div(:id => 'txt').text
#=> "22:48:36"
对不起,我是法国人。。。。lol这个脚本允许刷新浏览器而不需要跳过一步,例如,当你必须登录时,你不能跳过一步。。。。。如果你有一个连接太多、带宽较低的网站。。。。。
我认为seeb会这样做:
module Watir
class WhenPresentDecorator
def method_missing(m, *args, &block)
unless @element.respond_to?(m)
raise NoMethodError, "undefined method `#{m}' for #{@element.inspect}:# {@element.class}"
end
begin
while !@element.present?
sleep(10)
puts "timed out, let's refresh"
@element.browser.refresh
end
rescue
else
@element.__send__(m, *args, &block)
end
end
end # WhenPresentDecorator
end