我使用selenium将网站表格中的数据转化为分析。我必须扫描并获得约1000行的表格。
我知道该页面有Javascript,它会自动更新DOM。但是这个表太多了,所以当我扫描我的代码时总会抛出异常。
我尝试使用此代码:
Boolean breakIt = true;
List<IWebElement> result = new List<IWebElement>();
while (true)
{
breakIt = true;
try
{
IWebElement baseTable = browser.FindElementById("column2");
ReadOnlyCollection<IWebElement> rowsTable = baseTable.FindElements(By.XPath("id('oTable')/table/tbody/tr"));
foreach (IWebElement rows in rowsTable) {
if (rows.FindElements(By.XPath("td")).Count == 10)
result.Add(rows);
}
if (breakIt)
{
break;
}
}
catch (StaleElementReferenceException ser)
{
if (ser.Message.Contains("element is not attached"))
{
browser.Refresh();
browser.WaitForPageToLoad();
browser.GoToFrame(browser.FindElementByXPath("//*[@id='form1']/div[3]/iframe"));
breakIt = false;
}
}
}
它抛出了一个例外:
陈旧元素引用:元素未附加到页面文档。
有任何想法解决我的问题吗?我认为使用多个Thread
是最好的方法。
但我尝试使用多个Thread
它也会返回异常。
我认为在获得rowsTable.Count
之后。除此/ 2。并创建两个线程运行吗?
答案 0 :(得分:6)
我处于类似情况。我的名单不是那么大,所以我提出的一些想法不适用于我的案例,因此我没有对它们进行测试。
假设表定期更新,那么如果第一个表扫描在StaleElementReferenceException
上失败,则第二个表扫描会在下一个静默期开始时启动,并且在下次更新发生之前很有可能成功。前提是您可以比更新周期更快地完成扫描。
waitForAngular()
是来自https://stackoverflow.com/a/30540634/6081394或来自https://stackoverflow.com/a/38657507/6081394的方法,或者一个接一个地使用这些方法以确保;)
var finished = false;
for (var i = 0; i < 10; i++)
{
try
{
waitForAngular()
// scan table here
finished = true;
break;
}
catch (StaleElementReferenceException e)
{
continue;
}
}
if (!finished)
{
// test flaked out
}
我自己这样做。
本地selenium比Remote更快,因此使用上一种方法,在页面更新之前完成表扫描的可能性要高得多。我知道,这是不现实的,但仍然是一种选择。
如果表只是刷新但数据(和行数)相同,您可以先计算表中的行数,然后一次检查10行,如果StaleElementReferenceException
则重试像以前一样。
您可以使用CSS查询行范围,请参阅https://stackoverflow.com/a/28061560/6081394
tr:nth-child(n+2):nth-child(-n+4)
JavaScript执行是事件驱动和单线程的。这可以保证当您注入的JavaScript运行时,更新页面的脚本不会。但是,可能会发生的情况是,当表处于更新过程中时脚本会被执行。你必须检测到,拯救,再次运行脚本,希望下次会更好。有关示例,请参阅https://stackoverflow.com/a/6285793/6081394。
如果我面对一张大桌子并快速更新,这就是我的追求方式。
AFAIK,selenium驱动程序最终在页面中执行JavaScript来完成工作,并且执行是单线程的,因为单个浏览器选项卡中的所有JavaScript执行都是单线程的。因此,您编写的任何多线程C#测试都将以序列化顺序依次执行Selenium操作。因此多线程不是解决方案。