我正在尝试编写一个爬虫程序,它从加载的页面抓取所有链接,并将所有请求和响应标头以及响应正文记录在某些文件中,例如XML或txt。我在新浏览器窗口中打开第一个加载页面的所有链接,所以我不会收到此错误:
Element not found in the cache - perhaps the page has changed since it was looked up
我想知道什么是另外的方式来发出请求并从所有链接接收响应,然后找到输入元素并从所有打开的窗口提交按钮。
我可以在某种程度上执行上述操作,除非打开的窗口在右上角的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 Webdriver或使用http.set_debug_output
的{{1}}获取响应正文的所有requeat和响应标头?
答案 0 :(得分:1)
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找到的所有元素添加到您迭代的单个数组变量中的。然后,当发生不好的事情时,需要一次救援(我假设你不想从那里自动退出,这就是为什么你只想把信息打印到屏幕上)。
学会干掉你的代码并使用外部宝石将帮助你以更快的速度实现你想要做的很多事情。