Python Selenium陈旧元素修复

时间:2014-11-18 20:28:36

标签: python selenium-webdriver

在python中使用Selenium时出现以下错误:

selenium.common.exceptions.StaleElementReferenceException: Message: u'stale element reference: element is not attached to the page document\n

有趣的是,错误会在for循环中的不同时间弹出。有时它通过例如。 4次迭代和其他时间,例如。 7。

正在运行的一些相关代码是:

for i in range(0, 22):
    u = driver.find_elements_by_id("data")
    text = u[0].get_attribute("innerHTML")
    driver.find_elements_by_class_name("aclassname")[0].click()

这个错误意味着什么,我可以尝试解决这个问题?

12 个答案:

答案 0 :(得分:16)

Selenium支持ExplicitImplicit等待。如果您认为等待一定的时间足以加载您的页面,请使用:

driver.implicitly_wait(secs)

但如果您想等待特殊事件(例如等待加载特定元素),您可以执行以下操作:

from selenium.webdriver.support.ui import WebDriverWait
...
...
def find(driver):
    element = driver.find_elements_by_id("data")
    if element:
        return element
    else:
        return False
element = WebDriverWait(driver, secs).until(find)

答案 1 :(得分:11)

这意味着该元素不再位于DOM中,或者已更改。

你在for循环中。想一想迭代过程中会发生什么:

  1. 点击元素(最后一行)时会发生一些变化
  2. 所以页面正在改变
  3. 您输入下一个迭代。现在正试图找到一个新元素(你在循环中的第一行)。
  4. 您找到了元素
  5. 完成更改
  6. 您尝试通过获取属性
  7. 来使用它
  8. 的Bam!元素是旧的。你在第4步得到它,但它在第5步完成了改变
  9. 以下代码可帮助您找到元素:

    from selenium.common.exceptions import NoSuchElementException
    from selenium.common.exceptions import StaleElementReferenceException
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions
    
    ignored_exceptions=(NoSuchElementException,StaleElementReferenceException,)
    your_element = WebDriverWait(your_driver, some_timeout,ignored_exceptions=ignored_exceptions)\
                            .until(expected_conditions.presence_of_element_located((By.ID, Your_ID)))
    

答案 2 :(得分:3)

除了此处的答案以外,如果您使用的是ActionChains,并且页面已更改,请确保重新实例化ActionChains对象(不要重用旧的对象),否则ActionChain将使用陈旧的DOM。即做到这一点;

action_chain = ActionChains(driver)     
action_chain.double_click(driver.find_element_by_xpath("//tr[2]/p")).perform()

或者更好,但不要使用实例化;

ActionChains(driver).double_click(driver.find_element_by_xpath("//tr[2]/p")).perform()

答案 3 :(得分:2)

当网页刷新或从不同窗口或表单切换回来并尝试访问元素时,用户将获得staleelementexception。

在try forexcept块中使用webdriverwait for for循环: EX:

我遇到staleelementexception的代码:

driver.find_element_by_id(tc.value).click()

driver.find_element_by_xpath(" xpath")。click()

修复:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver.find_element_by_id(tc.value).click()
for i in range(4):
   try:
        run_test = WebDriverWait(driver, 120).until( \
        EC.presence_of_element_located((By.XPATH, "xpath")))
        run_test.click()
        break
   except StaleElementReferenceException as e:
        raise e

答案 4 :(得分:2)

对于我的python脚本,在相当简单的页面上,上述所有解决方案均无效。我在这里找到了最简单的解决方法-> https://www.softwaretestingmaterial.com/stale-element-reference-exception-selenium-webdriver/。点击之前只是刷新。

driver.refresh()
driver.find_element_by_id('normal').click()

注意:我使用的是driver.implicitly_wait(5)而不是显式等待,但这在两个选项中都可以使用。

答案 5 :(得分:1)

>>>Stale Exceptions can be handled using **StaleElementReferenceException** to continue to execute the for loop.  

from selenium.common import exceptions  

# and customize your code of for loop as:  

for i in range(0, 22):  
   try:  
        u = driver.find_elements_by_id("data")  
        text = u[0].get_attribute("innerHTML")  
        driver.find_elements_by_class_name("aclassname")[0].click()  
   except exceptions.StaleElementReferenceException:  
        pass

答案 6 :(得分:1)

就我而言,问题

陈旧元素参考:元素未附加到页面文档

是因为我尝试使用 actions.move_to_element(element).perform()在通过 Selenium标签创建的操作上。

因此解决方案是在打开新标签后创建新的动作实例:

actions = ActionChains(browser)
actions.move_to_element(element).perform()

答案 7 :(得分:1)

from selenium.webdriver.support.expected_conditions import staleness_of

上面的导入为我节省了一天。

答案 8 :(得分:1)

这取决于您使用的网站。

如果您有一个不会自行更改的网站,请使用 Emilio 的答案。 WebDriverWait(...).until(...) 是网站的正确/最佳解决方案,网站本身不会改变(并且仅通过用户交互):

WebDriverWait(driver, delay, ignored_exceptions=(NoSuchElementException,StaleElementReferenceException)).until(expected_conditions.presence_of_element_located((By.ID, "my_id"))).click()

(有关解释,请参阅 Emilio 的回答)

如果您使用一个站点,该站点会因来自服务器的推送或基于时间或类似的内容而发生变化,那么唯一可行的解​​决方案是像 Rashids 的回答一样重试。

def retry_func(func, max_tries=MAX_TRIES):
    for i in range(max_tries):
        try:
            return func()
        except Exception as e:
            if i >= max_tries - 1:
                raise e


def click_button_helper(driver, selector, selector_type=By.XPATH, delay=DELAY, ignored_exceptions=IGNORED_EXCEPTIONS):
    WebDriverWait(driver, delay, ignored_exceptions=ignored_exceptions).until(
        EC.presence_of_element_located((selector_type, selector))).click()


def click_button(driver, selector, selector_type=By.XPATH, delay=DELAY, ignored_exceptions=IGNORED_EXCEPTIONS,
                 max_tries=MAX_TRIES):
    retry_func(lambda: click_button_helper(driver, selector, selector_type, delay, ignored_exceptions), max_tries)

因为,抱歉@Emilio,您的回答没有解决像 Sylvan LE DEUNFF 提到的那样的具体情况。

仍然可能出现以下竞争条件(并且不能通过 WebDriverWait(...).until(...) 解决,但通常通过重试):

  1. 页面正在发生变化(例如,在点击问题后)
  2. 我们正在尝试查找元素。
  3. WebDriverWait(...).until(...) 等待我们直到我们的 expected_conditions 被满足(所以基本上直到它完成改变)
  4. 我们找到了元素
  5. 它再次开始变化(通过推送,通过到达时间步,...)
  6. 我们尝试使用它
  7. 呸!元素又旧了。

答案 9 :(得分:1)

就我而言,一种情况: 我查询了一次元素,并将其分配给一个变量以供重用,

captchaInput = driver.find_element_by_css_selector('input[name="CaptchaCode"]')

然后它冒着StaleElementReferenceException的风险,用上面的代码再次查询元素有助于消除异常。

答案 10 :(得分:0)

这是解决此问题的python解决方案:

onVerificationCompleted(PhoneAuthCredential cred)

答案 11 :(得分:0)

我想在这里添加一个对我有用的解决方案。

刷新同一页面的内容区域后,我试图访问网页顶部菜单面板中的按钮,这给我带来以下错误,

    raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.StaleElementReferenceException: Message: The element reference of <span id="dk1-combobox" class="dk-selected combinationText visibleElements "> is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed

然后,我开始搜索解决方案以单击网页上的陈旧元素。经过两天的思考和谷歌搜索,我找到了解决方案。

要访问页面上的陈旧元素,首先,我们需要将鼠标放在特定部分上并执行单击选项

EditReport1 = driver.find_element_by_id('internalTab1')
ActionChains(driver).move_to_element(EditReport1).click(EditReport1).perform()

move_to_element将鼠标移到需要访问的陈旧元素上,一旦我们成功控制了元素,就可以完成点击操作。

这对我有用。如果有人发现它可以正常工作,请也评论您的,这将对以后的工作有所帮助。

谢谢