【发布时间】:2023-04-06 07:33:01
【问题描述】:
我正在尝试使用 C# 中的 Selenium 抓取一个页面,该页面有几个页面,我可以通过单击页面上的“下一步”按钮来浏览这些页面。我通常会收到一个错误,即存在 stale element reference,只有当我在没有断点的情况下运行它时才会发生这种情况。如果我一步一步完成程序,它工作得很好。我假设 Selenium 在不等待的情况下跳过重要的东西(即使我实现了等待方法)。
对代码来说,这是问题的主要逻辑:
foundVacancies.AddRange(FindVacanciesOnPage());
const string nextBtnXPath = "//*[@id=\"ContainerResultList\"]/div/div[3]/nav/ul/li[8]/a";
if (Driver.FindElements(By.XPath(nextBtnXPath)).Count != 0)
{
while (TryClickingNextButton(nextBtnXPath))
{
foundVacancies.AddRange(FindVacanciesOnPage());
}
}
此方法首先获取第一页上的所有项目并将它们添加到foundVacancies 列表中。之后,它将尝试寻找“下一步”按钮,如果没有足够的项目,该按钮并不总是存在。如果是,它会尝试单击它,刮掉页面,然后再次单击它,直到没有剩余页面为止。这在调试的时候效果很好,但是正常运行就很不对劲了。
获取页面所有item的方法,以及出错的位置:
private IEnumerable<string> FindVacanciesOnPage()
{
var vacancies = new List<string>();
var tableContainingAllVacancies = Driver.FindElement(By.XPath("//*[@id=\"ContainerResultList\"]/div/div[2]/div/ul"));
var listOfVacancies = tableContainingAllVacancies.FindElements(By.XPath(".//li/article/div[1]/a"));
foreach (var vacancy in listOfVacancies)
{
vacancies.Add(vacancy.FindElement(By.XPath(".//h2")).Text);
}
return vacancies;
}
这些项目在一个<ul> HTML 标记中,并有<li> 孩子,我将一一进行,并获取它们的内部文本。陈旧元素错误发生在foreach 循环中。我假设网络驱动程序没有时间重新加载 DOM,因为它在断点时工作。但是,我确实有一种方法可以等待页面完全加载,这是我在转到下一页时使用的方法。
private bool TryClickingNextButton(string nextButtonXPath)
{
var nextButton = Driver.FindElement(By.XPath(nextButtonXPath));
var currentUrl = Driver.Url;
ScrollElementIntoView(nextButton);
nextButton.Click();
WaitUntilLoaded();
var newUrl = Driver.Url;
return !currentUrl.Equals(newUrl);
}
我正在比较新旧 URL 以确定这是否是最后一页。 WaitUntilLoaded 方法如下所示:
var wait = new WebDriverWait(Driver, TimeSpan.FromSeconds(30));
wait.Until(x => ((IJavaScriptExecutor) Driver).ExecuteScript("return document.readyState").Equals("complete"));
奇怪的是,有时 Web 驱动程序在加载第一页后立即关闭,没有任何错误或任何结果。我花了很多时间调试和搜索 SO,但似乎找不到任何信息,因为代码在通过断点时运行良好。
我只尝试过 Chrome,有无无头模式,但我不认为这可能是 Chrome 问题。
“下一步”按钮具有以下 HTML:
<a href="" data-jn-click="nextPage()" data-ng-class="{'disabled-element':currentPage === totalPages}" tabindex="0">
<span class="hidden-md hidden-sm hidden-xs">Next <span class="icon icon-pagination-single-forward"></span></span>
<span class="hidden-lg icon icon-pagination-forward-enable"></span>
</a>
我找不到data-jn-click 是什么。我试图只执行 JavaScript nextPage();,但这并没有做任何事情。
【问题讨论】:
-
当您尝试查找下一个 (,next...)
.//h2'sText时,我感觉到网页是动态更新的。或者,当您开始查找第一个文本时,页面没有完全加载。我建议给予一定的等待时间并使用FindElements而不是多个FindElements 并将找到的每个元素添加到“空缺”列表中,这应该会给您带来更好的性能和可靠性。 -
我认为 Selenium 能够等待特定类被加载,这有助于您的测试更加健壮。检查此链接seleniumhq.github.io/selenium/docs/api/dotnet/html/…
-
@kurakura88 我认为你是对的,我编辑了我的问题并添加了按钮/链接 HTML。我不知道“data-jn-click”到底是什么。我会尝试实现一些东西,等待一两秒钟,看看它做了什么。
-
@sjmarsh 我尝试在我的问题中使用 JavaScript 方法等待,但我也会尝试等待我需要的元素,看看它是否有效!会让你知道的。
-
您是否必须更改页面的状态才能定位过时的元素?如果您必须翻页或单击任何链接/按钮,那么以前未显示的元素将变得陈旧,因为它们的 css 将发生变化
标签: c# selenium selenium-webdriver web-scraping selenium-chromedriver