【问题标题】:How to avoid StaleElementReferenceException in Selenium - Python如何避免 Selenium 中的 StaleElementReferenceException - Python
【发布时间】:2017-02-23 01:58:28
【问题描述】:

我一直在编写 Python Selenium 脚本,似乎无法令人满意地解决我遇到的这个 StaleElementReferenceException。

我的页面已加载并单击一个按钮,该按钮打开一个表单,允许用户将新信用卡添加到订单中。此时,我执行 WebDriverWait 以暂停脚本,直到此表单上的 Save 按钮变得可见。此时,重新创建页面对象,因为它已更改,我的意图是填充字段并保存卡片。

问题是刷新页面对象后脚本失败并出现 StaleElementReferenceException。我的理解是 WebDriverWait 将暂停执行,让页面有时间加载所有需要加载的元素,但这似乎没有发生。相反,刷新页面对象中的某些内容是陈旧的并导致错误(每次创建对象的不同部分)。

如果我只是取消注释 'time.sleep(2)' 行,那么这个脚本运行良好,它会通过。所以我知道我只需要在刷新对象之前给页面时间来正确重新加载。 WebDriverWait 似乎并没有为我有效地做到这一点。

有没有更正确的方法可以在没有 sleep 命令的情况下做到这一点?

checkout = CheckoutProcess(self.driver)

# Add Credit Card
checkout.add_credit_card()

# Wait for form to display
WebDriverWait(self.driver,30).until(
    expected_conditions.presence_of_element_located((By.CLASS_NAME, 'total')))

# time.sleep(2)

# Refresh the page object so form can be filled in
checkout = CheckoutProcess(self.driver)  # Script Fails Here
checkout.populate_credit_card_data(
    credit_card_name, credit_card_number,
    credit_card_expiration_date, credit_card_cvc)
checkout.click_credit_card_save_button()

【问题讨论】:

  • 您需要在问题中添加更多信息。 CheckoutProcess 的代码在哪里?向我们展示确切的堆栈跟踪。另外,您正在测试哪个网址?顺便说一句,您是否使用自定义框架(围绕硒)来完成您的工作,而不是纯硒?
  • 我的 0.02 美元...不要在实例化页面对象时刮掉页面。使用元素时刮掉页面。例如,在.populate_credit_card_data() 中为每个元素执行.find_*,执行.send_keys(),等等。这将消除陈旧元素异常。
  • 另外...我支持 testerjoe2,因为我们需要查看 CheckoutProcess() 的代码。您可能在没有先获取它的情况下引用了某个元素......或者在获取和使用它变得陈旧的地方之间有一段时间。您可能需要一种确定页面是否已完成加载的好方法。
  • 当 CheckoutProcess 被实例化时,它有一些变量填充了页面中的数据。我将它用于一些测试脚本,但大多数不需要这些数据。大多数情况下,这些变量填充得很好,但在这种情况下并非如此。他们在此脚本中从运行到运行的更改失败的地方。我注释掉了那行代码,现在只需要调用填充该数据的函数即可。解决这个问题应该付出很小的代价。

标签: python selenium


【解决方案1】:

当您正在交互的元素被销毁然后重新创建时,会引发 StaleElementReferenceException。如今,大多数复杂的网页都会在用户与之交互时动态移动内容,这需要销毁和重新创建 DOM 中的元素。

尝试做

wait.until(ExpectedConditions.stalenessOf(whatever element));

wait.until(ExpectedConditions.presenceOfElementLocated(By.id("whatever elemnt")))

希望对你有帮助

【讨论】:

  • 我已经提取了我想要点击的所有链接,它们是

    标签。使用 link_list = browser.find_by_tag('h3')。然后我遍历它并单击每个链接。我能够存储所有抓取的数据,但是它给了我一个错误,阻止转到下一页。有什么帮助吗?谢谢。

【解决方案2】:

我遇到了同样的问题,并通过实现这个在捕获异常时重试的包装器来解决它:

from selenium.common.exceptions import StaleElementReferenceException

def _loop_is_text_present(text, max_attempts=3):
    attempt = 1
    while True:
        try:
            return self.browser.is_text_present(text)
        except StaleElementReferenceException:
            if attempt == max_attempts:
                raise
            attempt += 1

灵感来自:http://darrellgrainger.blogspot.com/2012/06/staleelementexception.html

【讨论】:

    【解决方案3】:
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.common.exceptions import StaleElementReferenceException
    
    
        def objectIdentificationUsingWaits(self, maxTimeOut, locatorProperties, locatorType = "xpath"):
            element = None
            try:
                WebDriverWait(self.driver, maxTimeOut, ignored_exceptions=[StaleElementReferenceException]).until(
                    EC.presence_of_element_located((self.getLocatorType(locatorType), locatorProperties)))
                element = self.driver.find_element(locatorType, locatorProperties)
            except:
                print("Exception occurred during object identification.")
            return element
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-14
      • 2019-04-02
      • 1970-01-01
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 2018-09-14
      相关资源
      最近更新 更多