eski öğe referansı: öğe sayfa belgesine eklenmemiş


97

Her bölümün altında birden fazla bağlantı olan bir listem var. Her bölümün aynı bağlantıları var, her bölümün altındaki belirli bir bağlantıya tıklamam gerekiyor. Aşağıdaki kodu yazdım ama çalıştırıldığında bana stale element reference: element is not attached to the page documenthata veriyor .

Bu benim kodum:

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

}

Bu HTML yapısı aşağıdaki gibidir

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

Hata İzleme:

    Exception in thread "main" 
org.openqa.selenium.StaleElementReferenceException: stale element 
reference: element is not attached to the page document

Yanıtlar:


81

İstisna veren satır nedir?

Bunun nedeni, başvurduğunuz öğenin DOM yapısından kaldırılmış olmasıdır.

IEDriver ile çalışırken aynı problemle karşılaşıyordum. Bunun nedeni, javascript'in ben başvurduktan sonra öğeyi bir kez daha yüklemesiydi, bu nedenle tarih referansım, kullanıcı arayüzünde doğru olsa bile var olmayan bir nesneye işaret ediyordu. Aşağıdaki geçici çözümü kullandım.

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

Aynı şeyin size yardımcı olup olmayacağını görün!


linkTexts [i] = e.getText (); çizgiler ikinci kez döngü yaparken hata veriyor
Patil Prashanth

1
Hatanın sayfa yenilemeden kaynaklandığı çözüldü. İlk olarak tüm bağlantı metinlerini bir String dizisi değişkenine kopyaladım ve daha sonra her bölümün altındaki gerekli bağlantılara tıklamak için for döngüsü kullandım. (WebElement e: LeftNavLinks) için {linkTexts [i] = e.getText (); i ++; } for (int j = 0; j <leftnavlen; j ++) {if (linkTexts [j] .equals (ben)) {String BenefitStatLi = "// * [@ id = 'kayan gezinme'] / li [% s ] / a "; driver.findElement (By.xpath (String.format (BenefitStatLi, j + 1))) tıklayın (); driver.findElement (By.xpath ("// * @ id = 'divContentHolder'] / div [1] / a [1]")) tıklayın (); }
Patil Prashanth

Yani aynı sebepten ötürü. Daha önce tanımlanan öğeler, sayfanın yenilenmesi nedeniyle DOM'dan kaldırıldı :)
Abhishek Singh

Evet gerçekten öyle. Çok teşekkür ederim @AbhishekSingh
Rahal Kanishka

Benim durumumda, gerekli eleman tıklandıktan sonra döngüde break ifadesine sahip olmadığım için bu istisnayı aldım.Bu tür durumlara da dikkat edin.
Raj Asapu

48

Bu sorunla her karşılaştığınızda, Hata aldığınız satırın üzerinde bir kez daha web öğesini tanımlayın .

Misal:

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, örneğin güncelleme eylemiyle değiştiğinden, bir StaleElementReferenceHata alıyorsunuz .

Çözüm:

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


Hey, bu hatamı çözmüş görünüyor. Ama daha önce tanımladığım aynı unsuru neden tanımlamam gerektiğini anlamıyorum.
Abhi

8

Bunu işlemek için aşağıdaki tıklama yöntemini kullanıyorum. Bu, öğeyi bulmaya ve tıklamaya çalışacaktır. Bulma ve tıklama arasında DOM değişirse, tekrar deneyecektir. Fikir, başarısız olursa ve hemen tekrar denersem ikinci girişimin başarılı olacağıdır. DOM değişiklikleri çok hızlıysa, bu işe yaramayacaktır.

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

8

Bu hataların iki genel nedeni vardır: Öğe tamamen silinmiştir veya öğe artık DOM'a ekli değildir.

Sizin durumunuz olup olmadığını zaten kontrol ettiyseniz, benimle aynı problemle karşı karşıya olabilirsiniz.

Selenium öğeyi ararken sayfanız tamamen yüklenmediği için DOM’daki öğe bulunamadı. Bunu çözmek için, Selenium'a öğenin tıklanmaya hazır olana kadar beklemesini söyleyen açık bir bekleme koşulu koyabilirsiniz.

from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))

Bakınız: https://selenium-python.readthedocs.io/waits.html


bu benim için çalıştı. Ayrıca belgenin bağlantısı, nasıl çalıştığını anlamada yardımcı oldu. Teşekkürler @Bruno_Sanches
Nikunj Kakadiya

4

Buradaki şey, koşullu ifadenizin dışında bir for döngüsü kullanmanızdır.

IF ifadenizdeki koşullar karşılandıktan sonra muhtemelen başka bir sayfaya gidersiniz, bu nedenle for döngüsü bir kez daha yinelemeye çalıştığında, eski öğe hatası alırsınız çünkü farklı bir sayfadasınız.

If ifadenizin sonuna bir ara ekleyebilirsiniz , bu benim için çalıştı.


Hatanın neden oluştuğunu anlamam biraz zaman aldı!
BEWARB

3

Üzerine tıklamak istediğiniz öğeyi bulduğunuzda döngüyü kesin. Örneğin:

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

2

Bu kodu kullanın:

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

Bu dene / yakala kodu aslında benim için çalıştı. Aynı eski öğe hatasını aldım.


1
Bu cevap, buradaki en çok oylanan cevaptan bir şekilde farklı mı?
SiKing

1

Bu, JS'de selenyumun daha yeni sürümlerinde yapılabilir (ancak tüm destekleyici bayatlık çalışacaktır)

 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'e göre sorunu anlamanız gerekiyor:

İstisna veren satır nedir? Bunun nedeni, başvurduğunuz öğenin DOM yapısından kaldırılmış olmasıdır.

ve artık ona başvuramazsınız (hangi öğenin kimliğinin değiştiğini hayal edin).

Kodu takip edin:

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

Şimdi merak edelim neden?

  1. btnTurnOff bir sürücü tarafından bulundu - tamam
  2. btnTurnOffile değiştirildi btnTurnOn- tamam
  3. btnTurnOnbir sürücü tarafından bulundu. - tamam
  4. btnTurnOnile değiştirildi btnTurnOff- tamam
  5. this.btnTurnOff.isDisplayed();Selenium anlamında artık var olmayan elementi çağırıyoruz - görüyorsunuz, mükemmel çalışıyor, ancak aynı düğmenin farklı bir örneği .

Olası çözüm:

  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

Benim durumumda, input type='date'sayfa yüklemede referans aldığım bir sayfam vardı, ancak onunla etkileşim kurmaya çalıştığımda, bunu gösterdi exceptionve bu, Javascriptkontrolümü manipüle ettiği için oldukça anlamlıydı, dolayısıyla belgeden ayrılmıştı ve re-getjavascript kontrol ile işini yaptıktan sonra referansına başvurmak zorunda kaldım. Yani, kodum istisnadan önce şöyle görünüyordu:

if (elemDate != null)
{ 
    elemDate.Clear(); 
    elemDate.SendKeys(model.Age);
}

İstisna oluşturulduktan sonraki kod:

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.

Böylece, şimdi kodunuzla daha fazla eylem gerçekleştirebilir veya kontrolün çalışmasını sağlamada başarısız olursa sürücüden çıkabilirsiniz.

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

Şimdiye kadar öğrendiğim bir şey, başarılı kod yürütme hakkında bilmek için istisnaları yakalamak iyi bir fikir değil, Ama bunu yapmak zorundaydım ve bunun work-aroundbu durumda iyi çalıştığını gördüm .

Not: Bütün bunları yazdıktan sonra, bu konudaki etiketleri fark ettim java. Bu kod örneği sadece gösteri amaçlıdır, C#dilde sorun yaşayan insanlara yardımcı olabilir . Veya javaçok C#özel bir kodu olmadığı için kolayca tercüme edilebilir .


-7

eleman eklenene kadar beklemek için bu kodu kullanın:

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
benim için işe yaramadı ama yine de ilginç bir yaklaşım
Yar

28
Bu herhangi bir anlam ifade etmiyor.
Sam

1
Bu mantıklı, "breakIt" değişken adı açısından en net değil. Bunun yaptığı şey, "öğe eklenmedi" hatası artık atılmadığı anda while (true) döngüsünden kopmaktır.
zımpara

'boolean doIt = true; while (doIt) {deneyin {// kodunuzu buraya yazın} catch (İstisna e) {if (e.getMessage (). içerir ("öğe eklenmemiş")) {doIt = false; }}} '
Tao Zhang

1
goto spirit gibi kokuyor
Eugene Baranovsky
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.