बासी तत्व संदर्भ: तत्व पृष्ठ दस्तावेज़ से जुड़ा नहीं है


101

मेरे पास सूची है जिसमें प्रत्येक अनुभाग के तहत कई लिंक हैं। प्रत्येक अनुभाग में समान लिंक होते हैं जिन्हें मुझे प्रत्येक अनुभाग के तहत एक विशेष लिंक पर क्लिक करने की आवश्यकता होती है। मैंने नीचे कोड लिखा है लेकिन जब यह निष्पादित होता है तो यह मुझे 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 के साथ काम करते समय मैं उसी समस्या का सामना कर रहा था। इसका कारण यह था कि जावास्क्रिप्ट ने तत्व को एक बार लोड करने के बाद मुझे एक बार संदर्भित किया था इसलिए मेरी तिथि संदर्भ एक अस्पष्ट वस्तु पर इंगित किया गया था, भले ही यह यूआई पर सही था। मैंने निम्नलिखित वर्कअराउंड का उपयोग किया।

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. पहले मैंने सभी लिंक टेक्स्ट को एक स्ट्रिंग ऐरे वेरिएबल में कॉपी किया और बाद में प्रत्येक सेक्शन के तहत आवश्यक लिंक पर क्लिक करने के लिए लूप का उपयोग किया। के लिए (WebElement e: LeftNavLinks) {linkTexts [i] = e.getText (); मैं ++; } (int j = 0; j <leftnavlen; j ++) {if (linkTexts [j] .equals (ben)) {स्ट्रिंग बेनिफिटस्टैटली = "// * [@ id = 'स्लाइडिंग-नेविगेशन-नेविगेशन] [/ li]% s ]/ए"; driver.findElement (By.xpath (String.Format (BenefitStatLi, j + 1))) पर क्लिक करें ()।; driver.findElement (By.xpath ( "// * @ id = 'divContentHolder'] / div [1] / एक [1]")) पर क्लिक करें ()।; }
पाटिल प्रशांत

तो यह उसी कारण के लिए था। पहले से पहचाने गए तत्व पृष्ठ ताज़ा होने के कारण DOM से हटा दिए गए थे :)
अभिषेक सिंह

हाँ वास्तव में यह करता है। बहुत बहुत धन्यवाद @AbhishekSingh
राहल कनिष्क

मेरे मामले में मुझे यह अपवाद मिला क्योंकि आवश्यक तत्व के क्लिक होने के बाद मेरे पास लूप में ब्रेक स्टेटमेंट नहीं है। ऐसी स्थितियों के लिए भी देखें।
राज आसापू

48

जब भी आप इस समस्या का सामना करते हैं, बस उस वेब तत्व को एक बार फिर उस पंक्ति के ऊपर परिभाषित करें जिसमें आपको एक त्रुटि मिल रही है।

उदाहरण:

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 क्यों बदल गया? धन्यवाद।
जुबैर ई.पू.

@JuBaerAD - यह पूरी तरह से फ्रेमवर्क (प्रतिक्रिया / वीयू / अन्य) पर जोर देगा। सरल "प्रत्यक्ष" HTML चीजों को बदलते देखना मुश्किल होगा। लेकिन एक ढांचे का उपयोग करते हुए यह अपने आप के लिए पूरी तरह से कुछ कर सकता है और इसका दुष्प्रभाव यह है। गलत? सबसे पहले और सबसे महत्वपूर्ण यूआई अभी भी काम करता है यानी रिएक्ट यूआई अभी भी काम करता है और आवश्यकतानुसार कार्य करता है? हां, कोई बात नहीं ... मैंने यूआई परीक्षण 20+ वर्षों के लिए किया है, मैंने यूआई देखा है जहां नियंत्रण को संदर्भित करने पर केवल वास्तविक नियंत्रण थे (परीक्षण नहीं करने के लिए मजेदार), और हर बार जब आप तकनीकी रूप से एक्सेस करते हैं तो एक नया नियंत्रण प्राप्त होता है .. एक ही बात यहाँ मुझे शक होगा ...
Dano

9

इस त्रुटियों के दो सामान्य कारण हैं: तत्व को पूरी तरह से हटा दिया गया है, या तत्व अब DOM से जुड़ा नहीं है।

यदि आपने पहले से ही जाँच कर ली है कि कहीं यह आपका मामला तो नहीं है, तो आप मेरे समान ही समस्या का सामना कर सकते हैं।

DOM में तत्व नहीं मिला है क्योंकि आपका पेज पूरी तरह से लोड नहीं है जब सेलेनियम तत्व की खोज कर रहा है। इसे हल करने के लिए, आप एक स्पष्ट प्रतीक्षा शर्त रख सकते हैं जो कि सेलेनियम को बताता है कि जब तक तत्व उपलब्ध न हो, तब तक प्रतीक्षा करें।

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
निकुंज काकड़िया

8

इसे संभालने के लिए, मैं निम्नलिखित क्लिक विधि का उपयोग करता हूं। यह तत्व को खोजने और क्लिक करने का प्रयास करेगा। यदि 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

यहाँ बात यह है कि आप अपने सशर्त विवरण के बाहर लूप के लिए उपयोग कर रहे हैं।

आपके 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();
}

इस कोशिश / कैच कोड ने वास्तव में मेरे लिए काम किया। मुझे वही बासी तत्व त्रुटि मिली।


1
क्या यह उत्तर यहां के शीर्ष मतदान से किसी तरह अलग है?
21

1

यह जेएस में सेलेनियम के नए संस्करणों में किया जा सकता है (लेकिन सभी सहायक 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

@ अभिषेक सिंह के अनुसार आपको समस्या को समझने की आवश्यकता है:

वो कौन सी लाइन है जो अपवाद देती है ?? इसका कारण यह है क्योंकि आपके द्वारा संदर्भित तत्व को 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();उस तत्व को कहते हैं जो सेलेनियम अर्थ में अब मौजूद नहीं है - आप इसे देख सकते हैं, यह पूरी तरह से काम करता है, लेकिन यह एक ही बटन का एक अलग उदाहरण है

संभव फिक्स:

  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
मेरे लिए काम नहीं किया, लेकिन अभी भी एक दिलचस्प दृष्टिकोण
यार

28
जो भी है किसी मतलब का नहीं है।
सैम

1
यह समझ में आता है, यह केवल इसके चर नाम "ब्रेक इट" के संदर्भ में सबसे स्पष्ट नहीं है। "तत्व संलग्न नहीं है" के रूप में जैसे ही वह करता है (सही) लूप से बाहर तोड़ दिया जाता है, त्रुटि अब फेंकी नहीं जा रही है।
एमरी

'बूलियन doIt = true; जबकि (doIt) {try {// अपना कोड यहां लिखें} catch (Exception e) {if (e.getMageage () शामिल है। ("तत्व संलग्न नहीं है")) {doIt = false; }}} '
ताओ झांग

1
गोटो स्पिरिट जैसी गंध
यूजीन बरानोवस्की
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.