У меня есть список, в каждом разделе которого есть несколько ссылок. В каждом разделе есть одинаковые ссылки. Мне нужно щелкнуть определенную ссылку под каждым разделом. Я написал приведенный ниже код, но при его выполнении возникает stale element reference: element is not attached to the page document
ошибка.
Это мой код:
public static void main(String[] args) throws InterruptedException
{
WebDriver driver = new ChromeDriver();
driver.navigate().to("url......");
driver.findElement(By.id("Login1_txtEmailID")).sendKeys("hourbank5@....com");
driver.findElement(By.id("Login1_txtPassword")).sendKeys("Testing1*");
driver.findElement(By.id("Login1_btnLogin")).click();
List<WebElement> LeftNavLinks=driver.findElements(By.xpath("//*[@id='sliding-navigation']//a"));
Thread.sleep(1000);
String ben="Benefit Status";
String[] linkTexts = new String[LeftNavLinks.size()];
int i = 0;
for (WebElement e : LeftNavLinks)
{
linkTexts[i] = e.getText();
System.out.print(i+" " + linkTexts[i]+"\n");
if(linkTexts[i].equals(ben))
{
String BenefitStatLi="//*[@id='sliding-navigation']/li[%s]/a";
System.out.print(i+" " + linkTexts[i]+"\n");
driver.findElement(By.xpath(String.format(BenefitStatLi,i))).click();
driver.findElement(By.xpath("//* [@id='divContentHolder']/div[1]/a[1]")).click();
}
i++;
}
}
}
Это структура HTML, как показано ниже
<div id="ucAdminMenu_divMenu">
<ul id="sliding-navigation">
<li class="sliding-element">
<a href=" ">Claims Status</a>
</li>
<li class="sliding-element">
<a href=" ">Eligibility Status</a>
</li>
<li class="sliding-element">
<h3>Section-1</h3>
</li>
<li class="sliding-element">
<a href=" ">Forms and Documents</a>
</li>
<li class="sliding-element">
<a href=" HourBank.aspx?id=002">Hour Bank</a>
</li>
<li class="sliding-element">
<h3>Section-2</h3>
</li>
<li class="sliding-element">
<a href=" ">Benefit Status</a>
</li>
<li class="sliding-element">
<a href=" ">Forms and Documents</a>
</li>
<li class="sliding-element">
<h3>Section-3</h3>
</li>
<li class="sliding-element">
<a href=" ">Forms and Documents</a>
</li>
<li class="sliding-element">
<h3>Testing Fund</h3>
</li>
<li class="sliding-element">
<a href=" ">Benefit Status</a>
</li>
<li class="sliding-element">
<a href=" ">Order ID Card</a>
</li>
</ul>
</div>
След ошибки:
Exception in thread "main"
org.openqa.selenium.StaleElementReferenceException: stale element
reference: element is not attached to the page document
источник
Всякий раз, когда вы сталкиваетесь с этой проблемой, просто снова определите веб-элемент над строкой, в которой вы получаете сообщение об ошибке.
Пример:
WebElement button = driver.findElement(By.xpath("xpath")); button.click(); //here you do something like update or save //then you try to use the button WebElement again to click button.click();
Поскольку модель DOM изменилась, например, в результате действия обновления, вы получаете сообщение об
StaleElementReference
ошибке.Решение:
WebElement button = driver.findElement(By.xpath("xpath")); button.click(); //here you do something like update or save //then you define the button element again before you use it WebElement button1 = driver.findElement(By.xpath("xpath")); //that new element will point to the same element in the new DOM button1.click();
источник
Чтобы справиться с этим, я использую следующий метод щелчка. Это попытается найти и щелкнуть элемент. Если DOM изменится между поиском и щелчком, он попытается снова. Идея в том, что если это не удалось, и я попытаюсь сразу же, вторая попытка будет успешной. Если изменения DOM происходят очень быстро, это не сработает.
public boolean retryingFindClick(By by) { boolean result = false; int attempts = 0; while(attempts < 2) { try { driver.findElement(by).click(); result = true; break; } catch(StaleElementException e) { } attempts++; } return result; }
источник
У этой ошибки есть две распространенные причины: элемент был полностью удален или элемент больше не прикреплен к модели DOM.
Если вы уже проверили, не ваш ли случай, вы можете столкнуться с той же проблемой, что и я.
Элемент в DOM не найден, потому что ваша страница не полностью загружается, когда Selenium ищет элемент. Чтобы решить эту проблему, вы можете указать явное условие ожидания, которое говорит Selenium ждать, пока элемент не станет доступным для нажатия.
from selenium.webdriver.support import expected_conditions as EC wait = WebDriverWait(driver, 10) element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))
См. Https://selenium-python.readthedocs.io/waits.html
источник
Дело в том, что вы используете цикл for вне условного оператора.
После выполнения условий в вашем операторе IF вы, вероятно, перейдете на другую страницу, поэтому, когда цикл for попытается повторить итерацию еще раз, вы получите ошибку устаревшего элемента, потому что вы находитесь на другой странице.
Вы можете добавить разрыв в конце оператора if, это сработало для меня.
источник
Просто прервите цикл, когда найдете элемент, по которому хотите щелкнуть. например:
List<WebElement> buttons = getButtonElements(); for (WebElement b : buttons) { if (b.getText().equals("Next"){ b.click(); break; }
источник
Используйте этот код:
public class LinkTest { public static void main(String[] args) { WebDriver driver = new FirefoxDriver(); driver.navigate().to("file:///C:/Users/vkiran/Desktop/xyz.html"); List<WebElement> alllinks =driver.findElements(By.xpath("//*[@id='sliding-navigation']//a")); String a[]=new String[alllinks.size()]; for(int i=0;i<alllinks.size();i++) { a[i]=alllinks.get(i).getText(); if(a[i].startsWith("B")) { System.out.println("clicking on this link::"+driver.findElement(By.linkText(a[i])).getText()); driver.findElement(By.linkText(a[i])).click(); } else { System.out.println("does not starts with B so not clicking"); } } } }
источник
try { WebElement button = driver.findElement(By.xpath("xpath")); button.click(); } catch(org.openqa.selenium.StaleElementReferenceException ex) { WebElement button = driver.findElement(By.xpath("xpath")); button.click(); }
Этот код try / catch действительно сработал для меня. У меня такая же ошибка устаревшего элемента.
источник
Это можно было бы сделать в новых версиях селена в JS (но все поддерживающие stalenessOf будут работать):
const { until } = require('selenium-webdriver'); driver.wait( until.stalenessOf( driver.findElement( By.css(SQLQueriesByPhpMyAdminSelectors.sqlQueryArea) ) ), 5 * 1000 ) .then( driver.findElement(By.css(SQLQueriesByPhpMyAdminSelectors.sqlQueryArea)) .sendKeys(sqlString) );
источник
Согласно @Abhishek Singh, вам нужно понять проблему:
и вы больше не можете ссылаться на него (представьте, какой идентификатор элемента изменился).
Следуйте коду:
class TogglingPage { @FindBy(...) private WebElement btnTurnOff; @FindBy(...) private WebElement btnTurnOn; TogglingPage turnOff() { this.btnTurnOff.isDisplayed(); this.btnTurnOff.click(); // when clicked, button should swap into btnTurnOn this.btnTurnOn.isDisplayed(); this.btnTurnOn.click(); // when clicked, button should swap into btnTurnOff this.btnTurnOff.isDisplayed(); // throws an exception return new TogglingPage(); } }
Теперь давайте зададимся вопросом, почему?
btnTurnOff
нашел водитель - окbtnTurnOff
был заменен наbtnTurnOn
- окbtnTurnOn
нашел водитель. - ОКbtnTurnOn
был заменен наbtnTurnOff
- окthis.btnTurnOff.isDisplayed();
элемент, который больше не существует в смысле Selenium - вы можете увидеть его, он работает отлично, но это другой экземпляр той же кнопки .Возможное исправление:
TogglingPage turnOff() { this.btnTurnOff.isDisplayed(); this.btnTurnOff.click(); TogglingPage newPage = new TogglingPage(); newPage.btnTurnOn.isDisplayed(); newPage.btnTurnOn.click(); TogglingPage newerPage = new TogglingPage(); newerPage.btnTurnOff.isDisplayed(); // ok return newerPage; }
источник
В моем случае у меня была страница, на которой была
input type='date'
ссылка, ссылка на которую я получил при загрузке страницы, но когда я попытался с ней взаимодействовать, она показала это,exception
и это было довольно значимо, посколькуJavascript
манипулировало моим контролем, поэтому оно было отделено от документа и мне пришлось обратиться к немуre-get
после того, как javascript выполнил свою работу с элементом управления. Итак, вот как мой код выглядел до исключения:if (elemDate != null) { elemDate.Clear(); elemDate.SendKeys(model.Age); }
Код после возникновения исключения:
int tries = 0; do { try { tries++; if (elemDate != null) { // these lines were causing the exception so I had break after these are successfully executed because if they are executed that means the control was found and attached to the document and we have taken the reference of it again. elemDate.Clear(); elemDate.SendKeys(model.Age); break; } } catch (StaleElementReferenceException) { System.Threading.Thread.Sleep(10); // put minor fake delay so Javascript on page does its actions with controls elemDate = driver.FindElement(By.Id(dateId)); } } while (tries < 3); // Try it three times.
Итак, теперь вы можете выполнять дальнейшие действия со своим кодом или можете выйти из драйвера, если он не смог заставить управление работать.
if(tries > 2) { // element was not found, find out what is causing the control detachment. // driver.Quit(); return; } // Hurray!! Control was attached and actions were performed. // Do something with it...
PS: Написав все это, я просто заметил теги, для которых была предназначена эта ветка
java
. Этот образец кода предназначен только для демонстрационных целей, он может помочь людям, у которых есть проблемы сC#
языком. Или его можно легко перевести, такjava
как в нем нет особогоC#
кода.источник
используйте этот код, чтобы дождаться прикрепления элемента:
boolean breakIt = true; while (true) { breakIt = true; try { // write your code here } catch (Exception e) { if (e.getMessage().contains("element is not attached")) { breakIt = false; } } if (breakIt) { break; } }
источник