元素引用: 元素没有附加到页面文档

我有一个列表,每个部分下面有多个链接。每个部分都有相同的链接,我需要点击每个部分下的特定链接。我已经写了下面的代码,但当它执行它给我的 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
616906 次浏览

例外的界限是什么?

原因是您引用的元素已从 DOM 结构中删除

我在使用 IEDriver 的时候也遇到了同样的问题。原因是 javascript 在我引用之后再次加载了元素,所以我的日期引用指向了一个不存在的对象,即使它就在 UI 中。我使用了以下变通方法:

try {
WebElement date = driver.findElement(By.linkText(Utility.getSheetData(path, 7, 1, 2)));
date.click();
}
catch(org.openqa.selenium.StaleElementReferenceException ex)
{
WebElement date = driver.findElement(By.linkText(Utility.getSheetData(path, 7, 1, 2)));
date.click();
}

看看能不能帮到你!

使用以下代码:

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");
}
}
}
}

使用此代码等待元素附加:

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


}

这里的问题是你在 If判断语句之外使用了一个 for 循环。

在满足 IF 语句中的条件之后,您可能会导航到另一个页面,因此当 for 循环尝试再次迭代时,您会得到陈旧的元素错误,因为您在另一个页面上。

你可以在 if 语句的末尾添加一个 休息,这对我很有用。

当您找到要单击的元素时,只需中断循环即可。 例如:

  List<WebElement> buttons = getButtonElements();
for (WebElement b : buttons) {
if (b.getText().equals("Next"){
b.click();
break;
}

为了处理它,我使用以下 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;
}
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 中硒的新版本中完成(但是所有支持 陈腐的的都可以工作) :

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

此错误有两个常见原因: 元素已被完全删除,或元素不再附加到 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

用爪哇语

import org.openqa.selenium.support.ui.ExpectedConditions;


WebDriverWait wait = new WebDriverWait(driver, 10);
element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));

见: https://www.selenium.dev/selenium/docs/api/java/org/openqa/selenium/support/ui/ExpectedConditions.html

无论何时您遇到这个问题,只要 再次定义 web 元素高于您得到一个错误的行。

例如:

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


根据@Abhishek Singh 的说法,你需要理解这个问题:

例外的界限是什么? 这是因为您引用的元素是来自 DOM 结构的 被移除了

而且不能再引用它(想象一下哪个元素的 ID 发生了变化)。

遵循代码:

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

现在,让我们想想为什么?

  1. btnTurnOff是一个司机发现的-OK
  2. btnTurnOffbtnTurnOn-ok 代替
  3. btnTurnOn是被一个司机发现的-好的
  4. btnTurnOnbtnTurnOff-ok 代替
  5. 我们在元素上调用 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操纵了我的控件,因此它从文档中分离出来,我必须在 javascript 执行了它对控件的作业之后,才能使用 re-get的引用。 这就是我的代码在异常出现之前的样子:

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

到目前为止,我学到的一件事就是,抓住例外去了解 关于成功的代码执行不是一个好主意,但是,我必须这样做 它和我发现这个 work-around在这种情况下工作得很好。

PS: 写完这些之后,我注意到这个线程是用于 java的标签。这个代码示例只是为了演示的目的,它可能有助于人们谁在 C#语言有问题。或者它可以很容易地翻译成 java,因为它没有多少 C#特定的代码。

在我的例子中,我使用的定位器有多个结果,因此它无法确定执行某个操作的正确元素,最终异常被抛出。 所以有了一个独一无二的定位器,解决了我的问题。

我有过好几次这样的问题。在我的一个案例中,接受的答案并没有解决我的问题,对我来说,问题是元素的中心不可点击,抛出的异常是误导“陈旧的元素引用: 元素没有附加到页面文档”。

对我来说,解决方法是滚动到元素,以确保元素的中心是可点击的。

为此,我使用了以下代码:

WebElement yourElement=
driver.findElement(By.id("yourElementId"));
((JavascriptExecutor) driver).executeScript("arguments[0].scrollIntoView(true);", yourElement);
yourElement.click();

希望这个能帮上忙!