Stale Element Reference: Element Is Not Attached to the Page Document

selenium element is not attached to the page document in selenium Java

You wrote "I'm trying to get data instantly..." Well, this could be a problem.

StaleElementReferenceException are thrown when a web element is obtained before the contents of the webpage refreshes or during the refresh process. In other words, it is obtained prematurely. The solution is to wait until the page finishes loading completely.

"Element is not attached to the page document" means that the web element is probably no longer in the HTML document.

There are two ways of obtaining a web element:

WebDriver driver = new ChromeDriver();
driver.findElement(...);

Assuming that you are on the correct page, findElement will attempt to locate the element without delay. If the page is in the process of loading, it will most likely result in the error mentioned in the OP's post. The correct way to fix this is to add an implicit wait.

WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS); // Time amount and time units are arbitrary.
// get to the page...
driver.findElement(...);

In the above snippet, from the moment implicitlyWait is called until the end of the test session, before any attempt to obtain a web element, the application will wait the minimum amount of time passed to the function; in my example that's 10 seconds.

A better way to do this is to use WebDriverWait class.

WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, 10); // max. wait time set to 10 seconds with default 500 ms polling interval

WebDriverWait has a three-argument variant where the third argument is the polling interval in milliseconds. For example, WebDriverWait(driver, 10, 100) will wait a maximum of 10 seconds, polling every 100 ms. Once the wait object is obtained, it will be used to obtain a WebElement object passing the correct expected condition provided by the ExpectedConditions class. For example, to wait until a button becomes "clickable" (both visible and enabled)

WebDriver driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.xpath(XPATH EXPRESSION HERE)));
button.click();

This approach, assuming you are already on the correct page, will attempt to locate the desired component the maximum amount of time passed to the WebDriverWait constructor before it times out. But, if the component is located AND the expected condition is reached before timing out, it will return the requested component. This is a better way to avoid stale element (although not completely).

Probably the best approach is to combine both of the approaches.

To start, set the implicit wait time as soon as the web driver instance is obtained

WebDriver driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

Then, navigate to the page

driver.navigate().to("https:.........");

Lastly, use the second approach to obtain the web element

WebDriverWait wait = new WebDriverWait(driver, 10);
WebElement button = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("...")));
button.click();

When implicit and explicit waits are used together, the chances of stale element issues is reduced to almost zero. You just have to be smart and always obtain the web element just before you are going to use it.... And DEFINITELY DO NOT put code like this in an endless loop.

Basically, this code works.... sort of.

public class TickerPageTest {
@Test
public void printTickerValueEndlessLoop() {
System.setProperty("webdriver.chrome.driver", "F:\\Users\\Hector\\webdriver\\chromedriver.exe");
WebDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
driver.get("https://coincheck.com/exchange/tradeview");

while (true) {
WebDriverWait wait = new WebDriverWait(driver, 10, 10);
WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("/html/body/div[2]/div[1]/div/div[2]/div[2]/div[2]/div[2]/div[1]/div[1]/span[3]")));
System.out.println(element.getTagName() + ":" + element.getText());
}
}
}

The above code outputs the following (most of the time)

span:5898999
...
span:5900895
...
span:5898999

The best bet is to wrap the interaction with the web element in a try/catch where you will catch the StaleElementReferenceException to ignore it and continue. In a real Selenium Test, you can you this strategy to retry obtaining the missed element, but in this case you don't need to.

try {
System.out.println(element.getTagName() + ":" + element.getText());
} catch (StaleElementReferenceException e) {
System.err.println("Test lost sync... this will be ignored.");
}

When I did this, after a few hundred lines (or more) I was able to catch a loss in synchronization:

span:5906025
Test lost sync... this will be ignored.
span:5906249

But, as you can see, I just ignored it and moved on to the next update.

Again Stale element reference: element is not attached to the page document

When you are doing

driver.findElement(completeButtonByXpath);

then at this time selenium is looking for *//button[text()='Complete'] xPath.

And probably at this time, it is not attached to HTML-DOM causing staleness.

Solution:

  1. A very simple solution is to put hardcoded sleep like this:

    Thread.sleep(5000);

and now look for WebElement completeButton = driver.findElement(completeButtonByXpath);


  1. Modify completeSession to Just have explicit waits.

    public void completeSession() {
    By completeButtonByXpath = By.xpath("*//button[text()='Complete']");
    //WebElement completeButton = driver.findElement(completeButtonByXpath);
    WebDriverWait wait = new WebDriverWait(driver, 30);
    wait.until(ExpectedConditions.elementToBeClickable(completeButtonByXpath)).click();
    }
  2. Retry clicking.

Code:

public void completeSession() {
By completeButtonByXpath = By.xpath("*//button[text()='Complete']");
WebElement completeButton = driver.findElement(completeButtonByXpath);
int attempts = 0;
while(attempts < 5) {
try {
completeButton.click();
break;
}
catch(StaleElementReferenceException staleException) {
staleException.printStackTrace();
}
attempts++;
}
}

Python Selenium Error: Message: stale element reference: element is not attached to the page document

You can use the normal click method, store the element in the list, get the element index and click on the index.

you can update your code with the below one

video_text = driver.find_elements_by_class_name("entry-thumbnails-link")
WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'entry-thumbnails-link')))
video_text[0].click()

The complete code will look like this

Vids = WebDriverWait(driver, 10).until(EC.visibility_of_any_elements_located((By.CLASS_NAME, 'entry-thumbnails-link')))
for title in Vids:
time.sleep(3)
actions = ActionChains(driver)
video_text = driver.find_elements_by_class_name("entry-thumbnails-link")
WebDriverWait(driver, 10).until(EC.presence_of_all_elements_located((By.CLASS_NAME, 'entry-thumbnails-link')))
video_text[0].click()
time.sleep(5)
VidUrl = driver.current_url
VidTitle = driver.find_element_by_xpath('//*[@id="post-69331"]/h1/a').text
try:
VidTags = driver.find_elements_by_class_name('tags')
for tag in VidTags:
VidTag = tag.find_element_by_tag_name('a').text

except NoSuchElementException or StaleElementReferenceException:
pass

with open('data.csv', 'w', newline='', encoding="utf-8") as f:
fieldnames = ['Title', 'Tags', 'URL']
thewriter = csv.DictWriter(f, fieldnames=fieldnames)

thewriter.writeheader()
thewriter.writerow({'Title': VidTitle, 'Tags': VidTag, 'URL': VidUrl})
driver.get(URL)
print('done')

Also try not to use these many sleep().

Python Selenium StaleElementReferenceException: Message: stale element reference: element is not attached to the page document

Since I have no credentials to enter that site I can only guess.

So my guess is: that site uses dynamic DOM.

It means that after the initial appearance the web elements continue re-build, so even after Selenium caught some specific element to be clickable or visible this element may instantly continue changing so that the initial element reference becomes stale.

You can try treat this problem by 2 ways:

  1. Set first wait condition, after that set a delay and after that another wait condition. Something like this:
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver,60)
wait.until(EC.element_to_be_clickable((By.XPATH,"//input[@id='ContentPlaceHolder1_rcmbCapacityTranch_Input']")))
time.sleep(2)
wait.until(EC.element_to_be_clickable((By.XPATH,"//input[@id='ContentPlaceHolder1_rcmbCapacityTranch_Input']"))).click()

  1. After you caught the element try clicking it. In case Stale element exception is raised wait until the element is clickable again and try clicking it again until click is succeed. With such loop you will normally make a click during 2-3 iterations.

    So please try this:
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver,60)
succeed = False
while !succeed:
try:
wait.until(EC.element_to_be_clickable((By.XPATH,"//input[@id='ContentPlaceHolder1_rcmbCapacityTranch_Input']"))).click()
succeed = True
except:
pass

ElementReferenceException: stale element reference: element is not attached to the page document

StaleElementReferenceException will be occurs only when your element is not present(vanished or not constructed till) in your website. please add wait conditions to check the visiblity of the element.

By optionXpath = By.xpath("your xpath fp goes here !");
WebDriverWait wait = new WebDriverWait(driver, 20);
wait.until(ExpectedConditions.elementToBeClickable(optionXpath));
wait.until(ExpectedConditions.visibilityOfElementLocated(optionXpath));
driver.findElement(optionXpath).click();

In case of not constructed :

you need to add wait conditions

In case of vanished :

yours actions on element is wrong. add screenshot just before your failure code and
recheck your code.

Selenium - stale element reference: element is not attached to the page

I haven't worked in c# but have worked on java/selenium. But,I can give you the idea to overcome staleness.

Generally we will be getting the Stale Exception if the element attributes or something is changed after initiating the webelement. For example, in some cases if user tries to click on the same element on the same page but after page refresh, gets staleelement exception.

To overcome this, we can create the fresh webelement in case if the page is changed or refreshed. Below code can give you some idea.(It's in java but the concept will be same)

Example:

 webElement element = driver.findElement(by.xpath("//*[@id='StackOverflow']"));
element.click();
//page is refreshed
element.click();//This will obviously throw stale exception

To overcome this, we can store the xpath in some string and use it create a fresh webelement as we go.

String xpath = "//*[@id='StackOverflow']";
driver.findElement(by.xpath(xpath)).click();
//page has been refreshed. Now create a new element and work on it
driver.findElement(by.xpath(xpath)).click(); //This works

In this case, we are collecting a group of webelements and iterating to get the text. But it seems there is some changes in the webelement after collecting the webelements and gettext throws staleness. We can use a loop and create the element on the go and get text.

for(int i = 0; i<5; i++)
{
String value = driver.findElement(by.xpath("//.....["+i+"]")).getText);
System.out.println(value);
}

Hope this helps you. Thanks.



Related Topics



Leave a reply



Submit