2

我正在尝试编写一个爬虫,它从加载的页面中爬取所有链接,并将所有请求和响应标头以及响应正文记录在某个文件中,例如 XML 或 txt。我正在新浏览器窗口中打开第一个加载页面的所有链接,所以我不会收到此错误:

Element not found in the cache - perhaps the page has changed since it was looked up

我想知道从所有链接发出请求和接收响应然后定位输入元素并从所有打开的窗口提交按钮的替代方法是什么。我可以在一定程度上做到这一点,除非打开的窗口在右上角有一个常见的站点搜索框,比如这个http://www.testfire.net上的一个。我想要做的是我想省略这样的常见框,以便我可以使用i.send_keys "value"webdriver 的方法用值填充其他输入并且不会收到此错误错误:在缓存中找不到元素 - 可能页面在查找后已更改.

从每个打开的窗口中检测和区分输入标签的方法是什么,以便在网站大多数页面上出现的常见输入标签中不会重复填充值。我的代码如下:

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_outputruby​​ 获取所有带有响应正文的requeat 和响应标头net/http

4

1 回答 1

1

Selenium 不是尝试构建“网络爬虫”的最佳选择之一。有时它可能太不稳定了,尤其是在遇到意想不到的情况时。Selenium WebDriver 是一个很好的工具,用于自动化和测试期望值和用户交互。相反,好的老式 curl 可能是网络爬行的更好选择。另外,我很确定有一些红宝石可以帮助您进行网络爬网,只需谷歌搜索即可!

但是,如果您要使用 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 将帮助你以更快的速度完成很多你想做的事情。

于 2013-04-14T04:11:32.610 回答