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()
Что означает эта ошибка и что я могу попытаться исправить?
Ответы
Ответ 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 или он изменился.
Вы внутри цикла. Подумайте, что происходит во время итераций:
- что-то меняется, когда вы нажимаете на элемент (последняя строка)
- Так что страница меняется
- Вы вводите следующую итерацию. Сейчас пытаемся найти новый элемент (ваша первая строка внутри цикла).
- Вы нашли элемент
- Заканчивает меняться
- Вы пытаетесь использовать его, получая атрибут
- Бам! Элемент старый. Вы получили его на шаге 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, e → exceptions.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 наведет указатель мыши на устаревший элемент, к которому мы должны получить доступ, как только мы получим контроль над элементом, операция нажатия успешно выполнена.
Это работает для меня. Если кто-то сочтет это работоспособным, пожалуйста, прокомментируйте его, что поможет другим в будущем.
Спасибо