我正在使用 Selenium
从此 site, 检索数据当我尝试单击 foreach
中的元素时遇到了一个小问题。
我想做什么
我正在尝试获取与特定赔率类别相关联的表格,在上面的链接中我们有不同的类别:
正如您从图片中看到的那样,我点击了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/