c# - 如何防止 foreach 循环内出现 "stale element"?

标签 c# selenium

我正在使用 Selenium 从此 site, 检索数据当我尝试单击 foreach 中的元素时遇到了一个小问题。

我想做什么

我正在尝试获取与特定赔率类别相关联的表格,在上面的链接中我们有不同的类别:

enter image description here

正如您从图片中看到的那样,我点击了Asian handicap -1.75 并且网站已经通过 javascript 生成了一个表格,所以在我的代码中我试图让该表格找到相应的元素并单击它。

代码

实际上我有两种方法,第一种称为 GetAsianHandicap,它遍历所有类别的赔率:

public List<T> GetAsianHandicap(Uri fixtureLink)
{ 
    //Contains all the categories displayed on the page
    string[] categories = new string[] { "-1.75", "-1.5", "-1.25", "-1", "-0.75", "-0.5", "-0.25", "0", "+0.25", "+0.5", "+0.75", "+1", "+1.25", "+1.5", "+1.75" };

    foreach(string cat in categories)
    {
        //Get the html of the table for the current category
        string html = GetSelector("Asian handicap " + asian);

        if(html == string.Empty)
            continue;

        //other code
    }
}

然后是点击搜索元素的方法GetSelector,设计是这样的:

public string GetSelector(string selector)
{
    //Get the available table container (the category). 
    var containers = driver.FindElements(By.XPath("//div[@class='table-container']"));

    //Store the html to return.
    string html = string.Empty;

    foreach (IWebElement container in containers)
    {
       //Container not available for click.
       if (container.GetAttribute("style") == "display: none;")
            continue;

       //Get container header (contains the description).
       IWebElement header = container.FindElement(By.XPath(".//div[starts-with(@class, 'table-header')]"));

       //Store the table description.
       string description = header.FindElement(By.TagName("a")).Text;

       //The container contains the searched category
       if (description.Trim() == selector)
       {
           //Get the available links.
           var listItems = driver.FindElement(By.Id("odds-data-table")).FindElements(By.TagName("a"));

           //Get the element to click.
           IWebElement element = listItems.Where(li => li.Text == selector).FirstOrDefault();

           //The element exist
           if (element != null)
           {
               //Click on the container for load the table.
               element.Click();

               //Wait few seconds on ChromeDriver for table loading.
               driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(20);

               //Get the new html of the page
               html = driver.PageSource;
           }

           return html;
       }

       return string.Empty;
    }

问题和异常详情

foreach 到达这一行时:

var listItems = driver.FindElement(By.Id("odds-data-table")).FindElements(By.TagName("a"));

我得到这个异常:

'OpenQA.Selenium.StaleElementReferenceException' in WebDriver.dll stale element reference: element is not attached to the page document

搜索错误意味着 html 页面源已更改,但在这种情况下,我将要单击的元素存储在一个变量中,将 html 本身存储在另一个变量中,因此我无法摆脱以修补此问题。

有人可以帮助我吗?

提前致谢。

最佳答案

我查看了您的代码,我认为您让它变得比需要的更复杂。我假设您想在单击其中一个障碍链接时抓取公开的表格。这是执行此操作的一些简单代码。它转储最终未格式化的元素文本,但您可以将其用作起点并根据需要添加功能。运行这段代码时,我没有遇到任何 StaleElementExceptions,也没有看到页面刷新,所以我不确定其他人看到了什么。

string url = "http://www.oddsportal.com/soccer/europe/champions-league/paok-spartak-moscow-pIXFEt8o/#ah;2";
driver.Url = url;

// get all the (visible) handicap links and click them to open the page and display the table with odds
IReadOnlyCollection<IWebElement> links = driver.FindElements(By.XPath("//a[contains(.,'Asian handicap')]")).Where(e => e.Displayed).ToList();
foreach (var link in links)
{
    link.Click();
}

// print all the odds tables
foreach (var item in driver.FindElements(By.XPath("//div[@class='table-container']")))
{
    Console.WriteLine(item.Text);
    Console.WriteLine("====================================");
}

我建议您多花些时间学习定位器。定位器非常强大,可以让您不必堆叠嵌套循环来寻找一个东西……然后是那个东西的 child ……然后是那个东西的 child ……等等。正确的定位器可以在页面的一次抓取中找到所有内容,从而节省大量代码和时间。

关于c# - 如何防止 foreach 循环内出现 "stale element"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51740750/

相关文章:

c# - 为什么要使用 DataSet.BeginInit 和 DataSet.EndInit

javascript - 如何设置浏览器视口(viewport)大小

java - 我们可以使用java更新受密码保护的Excel工作表的行和列吗?

javascript - 在 ASP.NET MVC 中导出 Excel 电子表格

c# - 您可以/如何在运行时为 PropertyGrid(对于 PCL)指定编辑器?

c# - 如何使用 Entity Framework 将实体加载到私有(private)集合中

java - 日历元素未被选中 - Selenium Webdriver

c# - 如何交叉引用类中的对象

javascript - Selenium Javascript - 如何找到祖 parent 和 parent

selenium - 无法使用 Selenium 3.5.x 通过 Behat/Mink 查找页面元素