Selenium - Stale元素引用:元素未附加到C#中的页面文档

时间:2016-06-13 03:48:04

标签: c# selenium

我使用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。并创建两个线程运行吗?

1 个答案:

答案 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。

本地selenium比Remote更快,因此使用上一种方法,在页面更新之前完成表扫描的可能性要高得多。我知道,这是不现实的,但仍然是一种选择。

多次扫描每个小范围的行。

如果表只是刷新但数据(和行数)相同,您可以先计算表中的行数,然后一次检查10行,如果StaleElementReferenceException则重试像以前一样。

您可以使用CSS查询行范围,请参阅https://stackoverflow.com/a/28061560/6081394

tr:nth-child(n+2):nth-child(-n+4)

注入JavaScript代码段并在那里进行检查。

JavaScript执行是事件驱动和单线程的。这可以保证当您注入的JavaScript运行时,更新页面的脚本不会。但是,可能会发生的情况是,当表处于更新过程中时脚本会被执行。你必须检测到,拯救,再次运行脚本,希望下次会更好。有关示例,请参阅https://stackoverflow.com/a/6285793/6081394

如果我面对一张大桌子并快速更新,这就是我的追求方式。

旁注

AFAIK,selenium驱动程序最终在页面中执行JavaScript来完成工作,并且执行是单线程的,因为单个浏览器选项卡中的所有JavaScript执行都是单线程的。因此,您编写的任何多线程C#测试都将以序列化顺序依次执行Selenium操作。因此多线程不是解决方案。