Подтвердить что ты не робот

StaleElementReferenceException в Python Selenium

Я получаю следующую ошибку при использовании Selenium в python:

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

Что означает эта ошибка и что я могу попытаться исправить?

4b9b3361

Ответ 1

Поддержка Selenium Explicit и Implicit Ожидает. Если вы считаете, что для загрузки вашей страницы достаточно ожидания определенного времени, используйте:

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)

Ответ 2

Это означает, что элемент больше не находится в DOM или он изменился.

Вы внутри цикла. Подумайте, что происходит во время итераций:

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

Ответ 3

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

Примечание. Python 3+: обновите exceptions.StaleElementReferenceException, eexceptions.StaleElementReferenceException как e

Ответ 4

Когда веб-страница обновилась или переключилась с другого окна или формы, и попытка получить доступ к элементу пользователя, вы получите staleelementexception.

Использовать webdriverwait в try --except block with for loop: 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

Ответ 5

Помимо ответов, приведенных здесь, если вы используете 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()

Ответ 6

Это решение Python для этой проблемы:

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

Ответ 7

Я хотел бы добавить еще одно решение, которое работает для меня.

Я пытался получить доступ к кнопке в верхней панели меню на моей веб-странице после обновления области содержимого на той же странице, что вызвало следующую ошибку:

    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 наведет указатель мыши на устаревший элемент, к которому мы должны получить доступ, как только мы получим контроль над элементом, операция нажатия успешно выполнена.

Это работает для меня. Если кто-то сочтет это работоспособным, пожалуйста, прокомментируйте его, что поможет другим в будущем.

Спасибо