StaleElementReferenceException on Python Selenium

2020-01-25 04:58发布

I am getting the following error while using Selenium in python:

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

Interestingly enough, the error pops up at different times in the for loop. Sometimes it gets through eg. 4 iterations and other times eg. 7.

Some of the relevant code being run is:

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()

What does this error mean and what is something I can try to fix this?

7条回答
贼婆χ
2楼-- · 2020-01-25 05:38
>>>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  

Note: Python 3+ : update exceptions.StaleElementReferenceException,e -> exceptions.StaleElementReferenceException as e

查看更多
家丑人穷心不美
3楼-- · 2020-01-25 05:41

Selenium Support Explicit and Implicit Waits. If you think waiting for certain amount of time is enough for your page to be loaded, use:

driver.implicitly_wait(secs)

but if you want to wait for a special event (e.g. waiting for a particular element to be loaded) you can do something like:

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)
查看更多
劫难
4楼-- · 2020-01-25 05:46

It means the element is no longer in the DOM, or it changed.

You are inside a for loop. Think what happens during the iterations:

  1. something changes when you click on the element (last line)
  2. So the page is changing
  3. You enter the next iteration. Now are trying to find a new element (your first line inside the loop).
  4. You found the element
  5. It finishes changing
  6. You try to use it by getting an attribute
  7. Bam! The element is old. You got it in step 4, but it finished changing on step 5

The following code may help you find the element:

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)))
查看更多
聊天终结者
5楼-- · 2020-01-25 05:46

I Would like to add one more solution here which is worked for me.

I was trying to access the button in the top menu panel on my webpage after refreshing the content area on the same page, Which gave me the following error,

    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

Then I started to search for the solution to click the stale element on the web page. After two days of thinking and googling, I got a solution.

To access the stale element on the page, first, we need to focus the mouse over the particular section and perform click option

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

move_to_element will move the mouse over the stale element which we need to access once we got our control on the element the click operation is successfully performed.

This is worked for me. If anyone finds it working please comment your's as well which will help some other in future.

Thank you

查看更多
时光不老,我们不散
6楼-- · 2020-01-25 05:49

Beyond the answers here, if you are using ActionChains, and the page has changed, be sure to reinstantiate your ActionChains object (dont reuse an old one), otherwise your ActionChain will be using a stale DOM. I.e. do this;

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

Or better yet dont use an instantiation;

ActionChains(driver).double_click(driver.find_element_by_xpath("//tr[2]/p")).perform()
查看更多
仙女界的扛把子
7楼-- · 2020-01-25 05:53

This is the python solution for this problem:

def clickAndCatchStaleRefException(locator):



    driver = sel2._current_browser()
    result = False
    attempts = 0

    locator = locator[6:]
    # This line is optional because sometimes you pass a xpath from a varibles file
    # that starts with 'xpath='. This should be omitted otherwise the find_element_by_xpath 
    # function will throw an error.
    # But if you pass an xpath directly you don't need this


    while attempts < 2:
        try:
            driver.find_element_by_xpath(locator).click()
            result = True
            break
        except EC as e:
            raise e
        finally:
            attempts += 1
    return result
查看更多
登录 后发表回答