Подтвердить что ты не робот

Ссылка на устаревший элемент: элемент не привязан к документу страницы

У меня есть список, который имеет несколько ссылок под каждым разделом. Каждый раздел имеет одинаковые ссылки, мне нужно нажать на конкретную ссылку под каждым разделом. Я написал код ниже, но когда он выполняется, он дает мне stale element reference: element is not attached to the page document ошибке 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("[email protected]");
    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
4b9b3361

Ответ 1

Что такое строка, которая дает исключение?

Причиной этого является то, что элемент, на который вы ссылались, удаляется из структуры DOM

У меня возникла такая же проблема во время работы с IEDriver. Причина заключалась в том, что javascript загрузил элемент еще один раз после того, как я упомянул, поэтому моя ссылка на дату указала на неиспользуемый объект, даже если это было правильно в пользовательском интерфейсе. Я использовал следующее обходное решение.

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

Посмотрите, поможет ли вам то же самое!

Ответ 2

Когда бы вы ни столкнулись с этой проблемой, просто определите веб-элемент еще раз над строкой, в которой вы получаете сообщение об ошибке.

Пример:

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

Ответ 3

Чтобы справиться с этим, я использую следующий метод щелчка. Это попытается найти и щелкнуть элемент. Если 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;
}

Ответ 4

Используйте этот код:

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

Ответ 5

Дело в том, что вы используете цикл for вне вашего условного оператора.

После выполнения условий в вашей инструкции IF вы, вероятно, переходите к другой странице, поэтому, когда цикл for пытается повторить итерацию, вы получаете ошибку устаревшего элемента, потому что вы находитесь на другой странице.

Вы можете добавить break в конце вашего оператора if, это сработало для меня.

Ответ 6

Эти ошибки имеют две общие причины: элемент был полностью удален или элемент больше не присоединен к 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.

Ответ 7

Просто перерыв цикла, когда вы найдете элемент, который вы хотите нажать на него. например:

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

Ответ 8

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 действительно работает для меня. Я получил ту же ошибку устаревшего элемента.

Ответ 9

Это может быть сделано в более новых версиях селена в 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)
  );

Ответ 11

Согласно @Abhishek Singh, вам нужно понять проблему:

Какая линия дает исключение?? Причина этого в том, что элемент, на который вы ссылались, удаляется из структуры DOM

и вы больше не можете ссылаться на него (представьте, какой идентификатор элемента изменился).

Следуйте коду:

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 был найден водителем - хорошо
  2. btnTurnOff был заменен на btnTurnOn - хорошо
  3. btnTurnOn был найден водителем. - Хорошо
  4. btnTurnOn был заменен на btnTurnOff - хорошо
  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;
  }

Ответ 12

В моем случае у меня была страница, на которой это был 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...

Кое-что из того, что я узнал до сих пор, заключается в том, что перехват исключений для успешного выполнения кода не очень хорошая идея, но мне пришлось это сделать, и я обнаружил, что этот work-around работает хорошо в этом случае.

PS: написав все это, я просто заметил теги, которые этот поток был для java. Этот пример кода только для демонстрации, он может помочь людям, у которых есть проблемы с языком C#. Или его можно легко перевести на java как он не имеет особого кода на C#.

Ответ 13

используйте этот код, чтобы подождать, пока элемент не будет прикреплен:

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

    }