我正在尝试编写一个爬虫程序,它可以抓取加载页面中的所有链接,并将所有请求和响应标头以及响应正文记录在某个文件中,例如XML或txt。我正在新浏览器窗口中打开第一个加载页面的所有链接,所以我不会收到此错误:
Element not found in the cache - perhaps the page has changed since it was looked up
我想知道发出请求并从所有链接接收响应的替代方法是什么,然后从所有打开的窗口中找到输入元素和提交按钮。我能够在一定程度上做上述操作,除非打开的窗口具有常见的站点 searh 框,例如右上角此 http://www.testfire.net 上的一个。我想做的是我想省略这些常见的框,以便我可以使用 webdriver 的方法用值填充其他输入i.send_keys "value"
并且不会收到此错误错误:在缓存中找不到元素 - 也许页面在查找后已更改。
从每个打开的窗口中检测和区分输入标签的方法是什么,以便该值不会在网站大多数页面上出现的常见输入标签中重复填充。我的代码如下:
require 'rubygems'
require 'selenium-webdriver'
require 'timeout'
class Clicker
def open_new_window(url)
@driver = Selenium::WebDriver.for :firefox
@url = @driver.get " http://test.acunetix.com "
@link = Array.new(@driver.find_elements(:tag_name, "a"))
@windows = Array.new(@driver.window_handles())
@link.each do |a|
a = @driver.execute_script("var d=document,a=d.createElement('a');a.target='_blank';a.href=arguments[0];a.innerHTML='.';d.body.appendChild(a);return a", a)
a.click
end
i = @driver.window_handles
i[0..i.length].each do |handle|
@driver.switch_to().window(handle)
puts @driver.current_url()
inputs = Array.new(@driver.find_elements(:tag_name, 'input'))
forms = Array.new(@driver.find_elements(:tag_name, 'form'))
inputs.each do |i|
begin
i.send_keys "value"
puts i.class
i.submit
rescue Timeout::Error => exc
puts "ERROR: #{exc.message}"
rescue Errno::ETIMEDOUT => exc
puts "ERROR: #{exc.message}"
rescue Exception => exc
puts "ERROR: #{exc.message}"
end
end
forms.each do |j|
begin
j.send_keys "value"
j.submit
rescue Timeout::Error => exc
puts "ERROR: #{exc.message}"
rescue Errno::ETIMEDOUT => exc
puts "ERROR: #{exc.message}"
rescue Exception => exc
puts "ERROR: #{exc.message}"
end
end
end
#Switch back to the original window
@driver.switch_to().window(i[0])
end
end
ol = Clicker.new
url = ""
ol.open_new_window(url)
指导我如何使用Selenium网络驱动程序或使用http.set_debug_output
ruby的net/http
来获取所有带有响应正文的requeat和响应标头?
Selenium不是尝试构建"网络爬虫"的最佳选择之一。它有时可能太不稳定,尤其是当遇到意外情况时。Selenium WebDriver是用于自动化和测试期望和用户交互的绝佳工具。相反,好的老式卷发可能是网络爬行的更好选择。另外,我很确定有一些红宝石可以帮助您进行网络爬行,只需谷歌搜索即可!
但是要回答实际问题,如果你要使用Selenium WebDriver:
我会制定一种过滤算法,您可以在其中将与之交互的元素的 HTML 添加到变量数组中。然后,当您转到下一个窗口/选项卡/链接时,它将检查变量数组,如果找到匹配的 HTML 值,则跳过该元素。
遗憾的是,SWD 不支持使用其 API 获取请求标头和响应。常见的解决方法是使用第三方代理来拦截请求。
=
===========现在我想解决您的代码中的几个问题。
我建议在迭代链接之前添加一个@default_current_window = @driver.window_handle
。这将允许您在调用 @driver.switch_to.window(@default_current_window)
时始终返回到脚本末尾的正确窗口。
在@links迭代器中,不要循环访问所有可能显示的窗口,而是使用 @driver.switch_to.window(@driver.window_handles.last)
。这将切换到最近显示的新窗口(每次单击链接只需要发生一次!
您可以通过执行以下操作来干掉输入和表单代码:
inputs = []
inputs << @driver.find_elements(:tag_name => "input")
inputs << @driver.find_elements(:tag_name => "form")
inputs.flatten
inputs.each do |i|
begin
i.send_keys "value"
i.submit
rescue e
puts "ERROR: #{e.message}"
end
end
请注意,我刚刚如何将您希望 SWD 找到的所有元素添加到您迭代的单个数组变量中。然后,当发生不好的事情时,需要一次救援(我假设你不想从那里自动退出,这就是为什么你只想将消息打印到屏幕上)。
学习干掉你的代码并使用外部 gem 将帮助你以更快的速度实现你正在努力做的很多事情。