我正在尝试使用C#中的Selenium刮取一个页面,通过单击页面上的“下一步”按钮可以浏览多个页面。我通常会得到一个错误的消息,即有一个过时的元素引用,只有当我在没有断点的情况下运行它时,该引用才会发生。如果我逐步执行该程序,则效果很好。我假设Selenium无需等待就跳过了重要的内容(即使我实现了wait方法)。对于代码,这是问题的主要逻辑: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列表中。之后,它将尝试寻找“下一步”按钮,如果没有足够的项目,该按钮将不会一直存在。如果是这样,它将尝试单击它,刮取页面,然后再次单击它,直到没有剩余的页面。这在调试时效果很好,但是正常运行时有一些错误。获取页面上所有项目以及发生错误的位置的方法: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循环中。我假设Web驱动程序没有时间重新加载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的问题。我不知道data-jn-click是什么。我试图只执行JavaScript nextPage();,但是什么也没做。
3 回答
杨魅力
TA贡献1811条经验 获得超6个赞
我没有使用C#的经验,所以如果有错,请不要介意。您正在使用findElements
并将其存储到var listOfVacancies
。我已经介绍了一些网站。你为什么不使用ReadOnlyCollection<IWebElement>
。最好将所有元素存储为List并对其进行遍历。所以代码变成了
ReadOnlyCollection<IWebElement> listOfVacancies = tableContainingAllVacancies.FindElements(By.XPath(".//li/article/div[1]/a"));
- 3 回答
- 0 关注
- 171 浏览
添加回答
举报
0/150
提交
取消