【问题标题】:Ruby Selenium Webdriver - Need to wait / sleep while page redirects (refreshes)Ruby Selenium Webdriver - 页面重定向(刷新)时需要等待/睡眠
【发布时间】:2014-07-01 14:21:10
【问题描述】:

我正在使用 Ruby selenium-webdriver gem 创建一个网络抓取/抓取脚本。我正在抓取的页面是通过 AJAX 加载的,并显示某个帐户的信息。如果您在下拉菜单中选择第二个帐号,页面会非常短暂地重定向到另一个 URL 并返回到原始 URL,只是通过 AJAX 加载了不同的信息。我希望能够抓取下拉选项中列出的两个帐号的信息。问题是 Selenium 执行抓取的速度比页面在下拉单击时重定向/重新加载的速度要快,所以我最终没有得到第二个帐户的信息。

def crawl_page
  browser = Selenium::WebDriver.for :firefox
  browser.manage.timeouts.implicit_wait = 10 # seconds 
  browser.navigate.to 'http://www.foobar.com'
  account_dropdown = Selenium::WebDriver::Support::Select.new(browser.find_element(:id, 'account'))
  account_dropdown.options.each do |option|
    option.click
    wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
    # this wait is not working because option is selected before redirect/refresh:
    wait.until { option.selected? }
    html = browser.page_source
    scrape_page(html)
  end
  browser.quit  
end

我尝试在单击后将sleep(3) 放在行上,但收到以下错误消息:

[remote server] resource://fxdriver/modules/web_element_cache.js:8180:in `fxdriver.cache.getElementAt': Element not found in the cache - perhaps the page has changed since it was looked up (Selenium::WebDriver::Error::StaleElementReferenceError)

我也尝试过使用 Selenium 的显式 wait 代码,但元素的 id 似乎在更新的页面上动态变化,如下所示:

wait = Selenium::WebDriver::Wait.new(:timeout => 10) # seconds
wait.until { browser.find_element(:id, 'titlexyz').displayed? }

导致出现错误消息,指出它已超时并且找不到元素:

~lib/selenium/webdriver/common/wait.rb:57:in `until': timed out after 10 seconds (Unable to locate element: {"method":"id","selector":"titlexyz"}) (Selenium::WebDriver::Error::TimeOutError)

有什么方法可以让它休眠或等待,而不必在页面上查找特定元素?

【问题讨论】:

    标签: ruby selenium-webdriver


    【解决方案1】:

    好的,多亏了SiKing的回答,我终于弄明白了。诀窍是计算下拉菜单的选项数量,并将其放入.times 循环中。然后在每次迭代中,我为下拉菜单实例化一个新的 Selenium 对象,找到正确的选项编号并单击它。我还让脚本休眠 5 秒,让它有机会进行重新加载/重定向。

    def crawl_page
      browser = Selenium::WebDriver.for :firefox
      browser.navigate.to 'http://www.foobar.com'
      account_dropdown = Selenium::WebDriver::Support::Select.new(browser.find_element(:id, 'account'))
    
      count = account_dropdown.options.count
      count.times do |option_num|
        account_dropdown = Selenium::WebDriver::Support::Select.new(browser.find_element(:id, 'account'))
        account_dropdown.options[option_num].click
        sleep 5
        html = browser.page_source
        scrape_page(html)
      end
    
      browser.quit  
    end
    

    【讨论】:

      【解决方案2】:

      我不做 ruby​​,所以我无法帮助你了解 ruby​​ 语法。

      每次重新加载页面时(在您的代码中每次执行 option.click),您拥有的所有 WebElement(您的 account_dropdown.find_elements(:css, 'option'))都不再有效!您必须将循环建立在其他东西的基础上——也许是下拉菜单中的项目数——并找到你想在循环中与 交互的每个元素!

      【讨论】:

      • 谢谢,但如果我在option.click 代码行之后放置puts option.text,它将正确显示正确的文本。 (我也可以运行p option,它们是不同的元素ID。)所以它似乎至少将这些元素保留在内存中足够长的时间来执行循环。问题是在我抓取它的page_source 之前,新的浏览器页面还没有加载。
      • 会很高兴看到您正在谈论的页面。在那之前,这一切都只是猜测。
      • 抱歉,没办法。这将涉及为您提供我们客户的一个登录名,而我们没有为此设置测试帐户。我确实认为你是对的。我认为这些元素只在内存中停留足够长的时间来快速使用它们做某事,但是一旦页面重定向,它就会丢失。我会尝试选项计数的想法。
      • 奇怪的是,我可以使用现有循环将选项值作为字符串获取并将它们存储在数组中,但是一旦我在新循环中使用它们来尝试迭代并找到每个选项在具有该值的页面上,然后单击它,我最终会收到一条错误消息,指出 The given selector option[value='foobar' is either invalid or does not result in a WebElement.
      猜你喜欢
      • 1970-01-01
      • 2017-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-07
      • 2012-07-12
      • 2017-05-06
      相关资源
      最近更新 更多