web-dev-qa-db-fra.com

Sélénium - référence d'élément périmé: l'élément n'est pas attaché à la page

J'essaie de comprendre pourquoi il y a une erreur pendant que j'essaie d'afficher des éléments extraits de sites Web . J'utilise également Google Chrome pour un navigateur.

chromeDriver.Navigate().GoToUrl("somewebsites");

chromeDriver.FindElement(By.Id("something.link.text")).Click();
chromeDriver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5));

Et cette autre partie de mon code

var item = chromeDriver.FindElementsByXPath("//*[starts-with(@id,\"g_1_\")]/td[3]/span");
foreach (var value in item)
{
    Console.WriteLine(value.Text); 
}

Chaque fois que j'utilise " chromeDriver.FindElement (By.Id (" quelquechose.link.text ")). Click ();" , cela donne une erreur. Je ne peux pas afficher les données que j'ai extraites. 

Dans le message d'erreur, il est écrit " OpenQA.Selenium.StaleElementReferenceException: 'référence de l'élément obsolète: l'élément n'est pas attaché à la page de document ". J'ai vérifié les autres messages, mais je ne l'ai pas compris. Comment puis-je le résoudre? 

Au moment où je lisais, le sélénium donne une réponse beaucoup plus rapide que le temps d’ouverture du site Web, ce qui donne l’erreur. En outre, il est rare que le sélénium ne puisse pas localiser l’élément. Toute suggestion?

EDIT: Si je supprime " .text " de la fonction d’affichage, " OpenQA.Selenium.Remote.RemoteWebElement " est affiché. Est-ce que les problèmes avec les chaînes?

EDIT2: Je peux conserver les données que j'ai extraites de sites Web comme ceci:

[i] = "System.Collections.ObjectModel.ReadOnlyCollection`1 [OpenQA.Selenium.IWebElement]" Pour cela, j'ai écrit quelque chose comme ceci:

string[] test= new string[100];

for (int i = 0; i < 100; i++)
{
     kaan[i] = driver.FindElements(By.XPath("//*[starts-with(@id,\"g_1_\")]/td[3]/span")).ToString();
}

Comment puis-je convertir le texte 

6
Kaan Taha Köken

Je n'ai pas travaillé en c # mais sur Java/Selenium. Mais je peux vous donner l’idée de vaincre la maigreur.

En règle générale, nous obtiendrons l'exception par exception si les attributs de l'élément ou quelque chose est modifié après le lancement de l'élément web. Par exemple, dans certains cas, si l'utilisateur essaie de cliquer sur le même élément de la même page mais après l'actualisation de la page, une exception staleelement est obtenue.

Pour résoudre ce problème, nous pouvons créer le nouveau Webelement au cas où la page serait modifiée ou actualisée. Le code ci-dessous peut vous donner une idée (c'est en Java mais le concept sera le même).

Exemple:

 webElement element = driver.findElement(by.xpath("//*[@id='StackOverflow']"));
 element.click();
 //page is refreshed
 element.click();//This will obviously throw stale exception

Pour surmonter cela, nous pouvons stocker le xpath dans une chaîne et l'utiliser pour créer un élément Web frais au fur et à mesure.

String xpath = "//*[@id='StackOverflow']";
driver.findElement(by.xpath(xpath)).click();
//page has been refreshed. Now create a new element and work on it
driver.fineElement(by.xpath(xpath)).click();   //This works

Dans ce cas, nous recueillons un groupe d’éléments Web et effectuons une itération pour obtenir le texte. Mais il semble y avoir quelques changements dans le webelement après la collecte des webelements et gettext jette la paresse. Nous pouvons utiliser une boucle et créer l'élément en déplacement et obtenir du texte.

for(int i = 0; i<5; i++)
{
   String value = driver.findElement(by.xpath("//.....["+i+"]")).getText);
   System.out.println(value);
}

J'espère que cela vous aide. Merci.

6
santhosh kumar

Ce type d'erreur est généralement causé par un DOM mis à jour. Je vous suggérerais que, sur toutes les pages contenant des appels javascript/ajax, attendiez réellement que ces appels soient terminés avant d'interagir avec le site. J'effectue généralement cette attente juste après le chargement de la page et lors de l'exécution d'une action qui déclenche des appels javascript/ajax et/ou des mises à jour du DOM. En pratique, cela signifie exécuter la fonction ci-dessous après le chargement de la page (ou avec laquelle il a été interagi), puis trouver l'élément avec lequel vous souhaitez interagir.

public void WaitForJqueryAjax() {
        int delay = MaxdelaySeconds;
        while(delay > 0) {
            Thread.Sleep(1000);
            var jquery = (bool)(this.driver as IJavaScriptExecutor)
                .ExecuteScript("return window.jQuery == undefined");
            if(jquery) {
                break;
            }
            var ajaxIsComplete = (bool)(this.driver as IJavaScriptExecutor)
                .ExecuteScript("return window.jQuery.active == 0");
            if(ajaxIsComplete) {
                break;
            }
            delay--;
        }
    }
1
Agent Shoulder

J'avais initialement ce problème mais je l'ai résolu en quelques tours

  • Attendez qu'un élément parent soit visible dans la page (peut être un div de conteneur parent)
  • Attendre que toute requête ajax (xhr) soit complétée autour de l'élément que vous essayez d'utiliser
  • (c'est l'astuce) ne stockez aucun élément en tant que valeur de propriété d'instance, recherchez toujours à la demande (cela vous aidera à partir de staleelement). Essayez une expression en c # 6, exemple Private IWebElement _parentContainer => _driver.FindElement (...) 

En outre, vous pouvez créer des contrôles de base abstraits et certaines méthodes d'extension pour IWebElement et effectuer des opérations de contrôle élémentaires lors de la recherche d'éléments.

0
Peter