在缓存中找不到元素 – 自从在Selenium Ruby Web驱动程序中查找以来页面可能已更改?

我正在尝试编写一个爬虫程序,它从加载的页面中抓取所有链接,并将所有请求和响应标题以及响应正文记录在某些文件中,例如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或使用ruby的net/http http.set_debug_output获取响应体的所有requeat和响应头?

Selenium不是尝试构建“网络爬虫”的最佳选择之一。 它有时太过火热,特别是遇到意外情况时。 Selenium WebDriver是一个用于自动化和测试期望和用户交互的强大工具。 相反,良好的老式curl可能是网络爬行的更好选择。 此外,我非常确定有一些ruby可以帮助您进行网页抓取,只需谷歌搜索它!

但要回答实际问题,如果您要使用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将帮助你以更快的速度实现你想要做的很多事情。