부실 요소 참조 : 요소가 페이지 문서에 첨부되지 않았습니다.


102

각 섹션 아래에 여러 링크가있는 목록이 있습니다. 각 섹션에는 각 섹션 아래의 특정 링크를 클릭하는 데 필요한 동일한 링크가 있습니다. 아래 코드를 작성했지만 실행하면 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

답변:


84

예외를주는 줄은 무엇입니까 ??

그 이유는 참조한 요소가 DOM 구조에서 제거 되었기 때문입니다.

IEDriver와 함께 작업하면서 같은 문제에 직면했습니다. 그 이유는 내가 참조 한 후 자바 스크립트가 요소를 한 번 더로드했기 때문에 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();
}

같은 것이 당신을 도울 수 있는지보십시오!


linkTexts [i] = e.getText (); 두 번째로 반복하면서 라인은 나에게 오류를 제공
파틸 프라 샨스에게

1
페이지 새로 고침 1로 인해 오류가 해결되었습니다. 먼저 모든 링크 텍스트를 문자열 배열 변수에 복사하고 나중에 for 루프에 사용하여 각 섹션 아래에 필요한 링크를 클릭했습니다. for (WebElement e : LeftNavLinks) {linkTexts [i] = e.getText (); i ++; } for (int j = 0; j <leftnavlen; j ++) {if (linkTexts [j] .equals (ben)) {String BenefitStatLi = "// * [@ id = 'sliding-navigation'] / li [% s ]/ㅏ"; driver.findElement (By.xpath (String.format (BenefitStatLi, j + 1))). click (); driver.findElement (By.xpath ( "// * @ id = 'divContentHolder'] / div [1] / a [1]")). click (); }
Patil Prashanth

그래서 같은 이유였습니다. 때문에 : 페이지 새로 고침에 이전 DOM에서 제거를 확인 요소
아비 쉑 싱

예 실제로 그것은 받았습니다 감사에게 많은 @AbhishekSingh을한다
라할 카니 슈카

필자의 경우에는 필요한 요소를 클릭 한 후 루프에 break 문이 없기 때문에이 예외가 발생했습니다.
Raj Asapu 2017

49

이 문제가 발생할 때마다 오류가 발생한 줄 위에 웹 요소를 다시번 정의하십시오 .

예:

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


이봐, 내 오류가 해결 된 것 같다. 그러나 이전에 정의한 동일한 요소를 정의해야하는 이유를 이해하지 못합니다.
Abhi

큰 도움. 그러나 동일한 변수에 대해 DOM이 변경된 이유를 설명해 주시겠습니까? 감사.
JuBaer AD

@JuBaerAD-프레임 워크 (react / vue / others)에서 완전히 가능하다고 주장합니다. 단순한 "직접"HTML은 변화하는 것을보기가 어려울 것입니다. 그러나 프레임 워크를 사용하면 자체적으로 완전히 무언가를 할 수 있으며 부작용은 이것입니다. 잘못된? 무엇보다도 UI가 여전히 작동합니까? 즉, React UI가 여전히 필요에 따라 작동하고 작동합니까? 예, 문제 없습니다 ... 저는 20 년 이상 UI 테스트를 해왔고, 컨트롤을 참조 할 때 실제 컨트롤 만있는 UI를 보았습니다 (테스트는 재미 없음). 기술적으로 액세스 할 때마다 새로운 컨트롤이 생겼습니다. ... 같은 일이 여기에 내가 ... 의심 것
단오

9

이 오류에는 두 가지 일반적인 원인이 있습니다. 요소가 완전히 삭제되었거나 요소가 더 이상 DOM에 연결되지 않았습니다.

귀하의 경우가 아닌지 이미 확인했다면 나와 같은 문제에 직면했을 수 있습니다.

Selenium이 요소를 검색 할 때 페이지가 완전히로드되지 않았기 때문에 DOM의 요소를 찾을 수 없습니다. 이를 해결하기 위해 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


이것은 나를 위해 일했습니다. 또한 문서에 대한 링크는 작동 방식을 이해하는 데 도움이되었습니다. 감사합니다 @Bruno_Sanches
Nikunj Kakadiya

8

이를 처리하기 위해 다음과 같은 클릭 방법을 사용합니다. 그러면 요소를 찾아 클릭합니다. 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

여기서는 조건문 외부에서 for 루프를 사용하고 있습니다.

IF 문의 조건이 충족되면 다른 페이지로 이동할 수 있으므로 for 루프가 한 번 더 반복을 시도하면 다른 페이지에 있기 때문에 부실 요소 오류가 발생합니다.

if 문 끝에 휴식 을 추가 할 수 있습니다 .


왜 오류가 발생했는지 이해하는 데 시간이 걸렸습니다!
BEWARB

3

클릭하려는 요소를 찾으면 루프를 끊으십시오. 예를 들면 :

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

2

이 코드를 사용하십시오.

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

1
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 코드는 실제로 저에게 효과적이었습니다. 동일한 부실 요소 오류가 발생했습니다.


1
이 답변이 여기에서 가장 많이 득표 한 답변과 어떻게 다른가요?
SiKing

1

이것은 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)
  );

0

@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 운전자가 찾았습니다.
  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;
  }

0

제 경우에는 input type='date'페이지를로드 할 때 참조한 페이지가 있었지만 상호 작용을 시도했을 때 이것을 보여 주었고 제 컨트롤을 조작 한 exception것처럼 상당히 의미가 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 해야했고이 경우에 이것이 잘 작동한다는 .

추신 :이 모든 것을 작성한 후이 스레드가 java. 이 코드 샘플은 데모 용으로, C#언어 문제가있는 사람들에게 도움이 될 수 있습니다. 또는 특정 코드 java가 많지 않기 때문에 쉽게 번역 할 수 있습니다 C#.


-7

이 코드를 사용하여 요소가 첨부 될 때까지 기다리십시오.

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

    }

1
나를 위해 작동하지 않았지만 여전히 흥미로운 접근 방식
Yar

28
이것은 그토록 의미가 없습니다.
Sam

1
의미가 있습니다. 변수 이름 "breakIt"측면에서 가장 명확하지 않습니다. "요소가 연결되지 않음"오류가 더 이상 발생하지 않는 즉시 while (true) 루프에서 빠져 나옵니다.
emery

'부울 doIt = true; while (doIt) {try {// 여기에 코드 작성} catch (예외 e) {if (e.getMessage (). contains ( "element is not attachment")) {doIt = false; }}} '
Tao Zhang

1
고토 정신 냄새
유진 Baranovsky에게
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.