我有一个无序的链接列表,我保存到一边,我想点击每个链接,并确保它进入一个真实的页面,并没有404,500等。
问题是我不知道该怎么做。是否有一些我可以检查的对象会给我http状态代码或其他什么?
mylinks = Browser.ul(:id, 'my_ul_id').links
mylinks.each do |link|
link.click
# need to check for a 200 status or something here! how?
Browser.back
end
答案 0 :(得分:5)
我的回答与Tin Man的回答类似。
require 'net/http' require 'uri' mylinks = Browser.ul(:id, 'my_ul_id').links mylinks.each do |link| u = URI.parse link.href status_code = Net::HTTP.start(u.host,u.port){|http| http.head(u.request_uri).code } # testing with rspec status_code.should == '200' end
如果你使用Test :: Unit测试框架,你可以测试如下,我认为
assert_equal '200',status_code
另一个示例(包括Chuck van der Linden的想法):检查状态代码并在状态不佳时注销URL。
require 'net/http' require 'uri' mylinks = Browser.ul(:id, 'my_ul_id').links mylinks.each do |link| u = URI.parse link.href status_code = Net::HTTP.start(u.host,u.port){|http| http.head(u.request_uri).code } unless status_code == '200' File.open('error_log.txt','a+'){|file| file.puts "#{link.href} is #{status_code}" } end end
答案 1 :(得分:4)
没有必要为此使用Watir。 HTTP HEAD
请求可让您了解网址是否已解决且速度更快。
Ruby的Net::HTTP
可以做到,或者你可以使用Open::URI
。
使用Open :: URI,您可以请求URI,然后返回页面。因为您并不真正关心页面包含的内容,所以您可以丢弃该部分,只返回是否有内容:
require 'open-uri'
if (open('http://www.example.com').read.any?)
puts "is"
else
puts "isn't"
end
优点是Open :: URI解决了HTTP重定向问题。缺点是它返回整页,所以它可能很慢。
Ruby的Net :: HTTP可以有所帮助,因为它可以使用HTTP HEAD
请求,这些请求不返回整个页面,只返回标头。这本身并不足以知道实际页面是否可以访问,因为HEAD响应可能会重定向到无法解析的页面,因此您必须遍历重定向,直到您不获得重定向,或者您收到错误。 Net :: HTTP文档有一个example可以帮助您入门:
require 'net/http'
require 'uri'
def fetch(uri_str, limit = 10)
# You should choose better exception.
raise ArgumentError, 'HTTP redirect too deep' if limit == 0
response = Net::HTTP.get_response(URI.parse(uri_str))
case response
when Net::HTTPSuccess then response
when Net::HTTPRedirection then fetch(response['location'], limit - 1)
else
response.error!
end
end
print fetch('http://www.ruby-lang.org')
同样,该示例是返回页面,这可能会减慢您的速度。您可以将get_response
替换为request_head
,这会返回get_response
之类的响应,这应该会有所帮助。
在任何一种情况下,你都需要考虑另一件事。很多网站都使用“meta refreshes”,这会导致浏览器在解析页面后使用备用URL刷新页面。处理这些需要请求页面并解析它,寻找<meta http-equiv="refresh" content="5" />
标签。
其他HTTP宝石(如Typhoeus和Patron)也可轻松执行HEAD
个请求,因此请查看它们。特别是,Typhoeus可以通过其伴侣Hydra
处理一些重负荷,让您轻松使用并行请求。
编辑:
require 'typhoeus'
response = Typhoeus::Request.head("http://www.example.com")
response.code # => 302
case response.code
when (200 .. 299)
#
when (300 .. 399)
headers = Hash[*response.headers.split(/[\r\n]+/).map{ |h| h.split(' ', 2) }.flatten]
puts "Redirected to: #{ headers['Location:'] }"
when (400 .. 499)
#
when (500 .. 599)
#
end
# >> Redirected to: http://www.iana.org/domains/example/
万一你没玩过一个,这就是响应的样子。它对于你所看到的那种情况非常有用:
(rdb:1) pp response
#<Typhoeus::Response:0x00000100ac3f68
@app_connect_time=0.0,
@body="",
@code=302,
@connect_time=0.055054,
@curl_error_message="No error",
@curl_return_code=0,
@effective_url="http://www.example.com",
@headers=
"HTTP/1.0 302 Found\r\nLocation: http://www.iana.org/domains/example/\r\nServer: BigIP\r\nConnection: Keep-Alive\r\nContent-Length: 0\r\n\r\n",
@http_version=nil,
@mock=false,
@name_lookup_time=0.001436,
@pretransfer_time=0.055058,
@request=
:method => :head,
:url => http://www.example.com,
:headers => {"User-Agent"=>"Typhoeus - http://github.com/dbalatero/typhoeus/tree/master"},
@requested_http_method=nil,
@requested_url=nil,
@start_time=nil,
@start_transfer_time=0.109741,
@status_message=nil,
@time=0.109822>
如果要检查的网址很多,请参阅Typhoeus中的Hydra example。
答案 2 :(得分:2)
关于watir或watir-webdriver是否应提供HTTP返回码信息,存在一些哲学争论。前提是Watir在DOM上模拟的普通“用户”不知道HTTP返回码。我不一定同意这一点,因为我对主要(性能测试等)的用例略有不同......但它就是它的本质。这个主题表达了关于区别的一些看法=&gt; http://groups.google.com/group/watir-general/browse_thread/thread/26486904e89340b7
目前没有简单的方法来确定来自Watir的HTTP响应代码而不使用代理/ Fiddler / HTTPWatch / TCPdump等补充工具,或降级到测试中的脚本编写的net / http级别...我个人喜欢使用firebug与netexport插件可以回顾测试。
答案 3 :(得分:0)
如果您拥有非常多的链接,之前的所有解决方案效率都很低,因为对于每个链接,它将与托管该链接的服务器建立新的HTTP连接。
我编写了一个单行bash命令,它将使用curl命令获取stdin提供的链接列表,并返回与每个链接对应的状态代码列表。这里的关键点是curl在同一个调用中占用了所有链接,它将重用 HTTP连接,这将大大提高速度。
然而,curl会将列表分成256个块,这仍然远远超过1!要确保重用连接,请先对链接进行排序(只需使用sort命令)。
cat <YOUR_LINKS_FILE_ONE_PER_LINE> | xargs curl --head --location -w '---HTTP_STATUS_CODE:%{http_code}\n\n' -s --retry 10 --globoff | grep HTTP_STATUS_CODE | cut -d: -f2 > <RESULTS_FILE>
值得注意的是,上述命令将遵循HTTP重定向,对于临时错误(超时或5xx)重试10次,当然只会获取标题。
更新:添加了--globoff,以便curl不会扩展任何网址,如果它包含{}或[]