Python Selenium陈旧元素修复

bil*_*999 37 html python dom selenium-webdriver

我在python中使用Selenium时收到以下错误:

selenium.common.exceptions.StaleElementReferenceException: Message: u'stale element reference: element is not attached to the page document\n
Run Code Online (Sandbox Code Playgroud)

有趣的是,错误在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()
Run Code Online (Sandbox Code Playgroud)

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

Nim*_*ush 18

硒支持ExplicitImplicit等待.如果您认为等待一定的时间足以填充您的页面,请使用:

driver.implicitly_wait(secs)
Run Code Online (Sandbox Code Playgroud)

但如果你想等待特殊事件(例如等待加载特定元素),你可以这样做:

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)
Run Code Online (Sandbox Code Playgroud)


Emi*_* M. 17

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

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

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

以下代码可以帮助您找到元素:

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)))
Run Code Online (Sandbox Code Playgroud)

  • 总体上很好的讨论。步骤 4-6 也可能非常微妙......我正在抓取的页面上有一个下拉列表,在加载的某个时刻,它被自身的精确副本替换,因此在选择一个页面时存在竞争条件`<option>`,单击它,然后提交导致几种可能错误之一的表单。 (3认同)
  • @Emilio M.这个答案对我不起作用。它给出了超时异常。如果有其他解决方案请帮忙 (2认同)

n00*_*00b 10

除了这里的答案之外,如果您正在使用 ActionChains,并且页面已更改,请务必重新实例化您的 ActionChains 对象(不要重用旧的),否则您的 ActionChain 将使用陈旧的 DOM。即这样做;

action_chain = ActionChains(driver)     
action_chain.double_click(driver.find_element_by_xpath("//tr[2]/p")).perform()
Run Code Online (Sandbox Code Playgroud)

或者最好不要使用实例化;

ActionChains(driver).double_click(driver.find_element_by_xpath("//tr[2]/p")).perform()
Run Code Online (Sandbox Code Playgroud)


小智 8

对于我的 python 脚本,在非常简单的页面上,上面提到的所有解决方案都不起作用。我在这里找到了 -> https://www.softwaretestingmaterial.com/stale-element-reference-exception-selenium-webdriver/解决我的问题的最简单方法。它只是在点击之前刷新。

driver.refresh()
driver.find_element_by_id('normal').click()
Run Code Online (Sandbox Code Playgroud)

注意:我使用 driver.implicitly_wait(5)而不是显式等待,但它适用于两个选项。


小智 6

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

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

我得到 staleelementexception 的代码:


driver.find_element_by_id(tc.value).click()
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)


Vis*_*hal 5

>>>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,e:
        print(e)
        pass  
Run Code Online (Sandbox Code Playgroud)

注意:Python 3+:将exceptions.StaleElementReferenceException,e- > exceptions.StaleElementReferenceException更新为e


Jey*_*ari 5

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

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

    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
Run Code Online (Sandbox Code Playgroud)

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

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

EditReport1 = driver.find_element_by_id('internalTab1')
ActionChains(driver).move_to_element(EditReport1).click(EditReport1).perform()
Run Code Online (Sandbox Code Playgroud)

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

这对我有用。如果有人发现它有效,请评论你的,这将在未来帮助其他人。

谢谢


Eug*_*nyi 5

就我而言,问题

过时的元素引用:元素未附加到页面文档

是因为我试图用 actions.move_to_element(element).perform()行动,从创建的硒标签。

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

actions = ActionChains(browser)
actions.move_to_element(element).perform()
Run Code Online (Sandbox Code Playgroud)