I have the following try statement, that basically finds a button that resets the current page I am in. In summary the page reloads,
try:
reset_button = D.find_element(By.XPATH,"//button[starts-with(@class,'resetBtn rightActionBarBtn ng-star-inserted')]")
reset_button.click()
D.implicitly_wait(5)
ok_reset_botton = D.find_element(By.ID,'okButton')
D.implicitly_wait(5)
print(ok_reset_botton)
ok_reset_botton.click()
D.implicitly_wait(5)
# Trying to reset current worksheet
except:
pass
print(D.current_url)
grupao_ab = D.find_element(By.XPATH,'//descendant::div[@][1]')
D.implicitly_wait(5)
grupao_ab.click()
The weird thing is every time that try statement get executed, I get the following log of error
selenium.common.exceptions.StaleElementReferenceException: Message: stale element reference: element is not attached to the page document
Which happens in the a following line of code according to the log
grupao_ab.click()
When I took a look at the reason given by selenium it say it is because the element is no longer on the given DOM, but the element grupao_ab
, is not even being defined in that page so why it is giving me that error? If any extra information is needed just comment.
CodePudding user response:
First of all, StaleElementReferenceException
means that the web element reference you trying to access is no more valid. This normally happens after the page was reloaded. This is exactly what happens here.
What happened is as following: you clicked on reset button and immediately after that you collecting the grupao_ab
element and shortly after that trying to click it. But between the moment you located the grupao_ab
element with grupao_ab = D.find_element(By.XPATH,'//descendant::div[@][1]')
and the line where you trying to click it, reloading started. So that previously collected web element, that actually is a reference to a physical element on the DOM, no more pointing to that web element.
What you can to do here is: after clicking on the refresh button set a short delay so that refreshing will start and after that wait for grupao_ab
element to become clickable. WebDriverWait
expected_conditions
explicit waits should be used for that.
Also, you should understand that D.implicitly_wait(5)
is not a pause command. It sets the timeout for find_element
and find_elements
methods to wait for presence of the searching element. Normally we never set this timeout at all since it's better to use WebDriverWait
expected_conditions
explicit waits, not implicitly_wait
implicitly waits. And you should never mix these two types of waits.
And even if you want to set implicitly_wait
to some value normally no need to set it again, this setting is applied to the entire driver
session.
Please try changing your code as following:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 20)
try:
wait.until(EC.element_to_be_clickable((By.XPATH, "//button[starts-with(@class,'resetBtn rightActionBarBtn ng-star-inserted')]"))).click()
wait.until(EC.element_to_be_clickable((By.ID, "okButton"))).click()
print(ok_reset_botton)
time.sleep(0.5) # a short pause to make reloading started
except:
pass
print(D.current_url)
#wait for the element on refreshed page to become clickable
wait.until(EC.element_to_be_clickable((By.XPATH, '//descendant::div[@][1]'))).click()