【问题标题】:Selenium WebDriver - StaleElementReferenceException that shouldn't be happeningSelenium WebDriver - 不应该发生的 StaleElementReferenceException
【发布时间】:2012-10-25 19:56:16
【问题描述】:

我在 Internet Explorer 中尝试了一些最初针对 Chrome 开发的脚本(并且在那里工作得很好),并发现 StaleElementReferenceExceptions 似乎是常态。显然这是因为 IE 太慢了?

据我了解,当您找到 WebElement,然后 DOM 发生变化,然后您尝试对该 WebElement 执行某些操作时,就会发生这些异常,这会使 Selenium 感到困惑,因为页面现在已经更改并且 WebElement 中的引用不存在有效期更长。如果这就是 StaleElementReferenceExceptions 发生的原因,那么我不知道为什么我会看到这个。

我有一个带有 Flash 播放器的新窗口,在 Flash 播放器播放视频后,我尝试从对象中获取一些参数。页面源码看起来有点像这样:

<object id="flashContent" width="100%" height="100%" type="application/x-shockwave-flash" name="flashContent" data="[redacted]" style="visibility: visible;">
    <param name="scale" value="noscale">
    <param name="wmode" value="opaque">
    <param name="allowfullscreen" value="true">
    <param name="allowscriptaccess" value="always">
    <param name="bgcolor" value="">
    <param name="SeamlessTabbing" value="false">
    <param name="flashvars" value="[redacted]">
</object>

我有兴趣阅读 flashvars 参数的值,所以我有以下代码:

text = driver.findElement(By.cssSelector("object#flashContent param[name='flashvars']")).getAttribute("value");

因此,我似乎无法缩短查找参数 WebElement 和获取其属性之间的时间,而 getAttribute 每次都抛出 StaleElementReferenceException 异常。我已经打开了页面源代码并观察了窗口——据我所知,没有任何变化。我尝试在一段时间内捕获异常并重试,希望我能遇到 DOM 安静且 WebElement 稳定的时间,但以下代码对我没有帮助:

    timer.start();
    while (true) {
        try {
            text = getDriver().findElement(By.cssSelector("object#flashContent param[name='flashvars']"))
                    .getAttribute("value");
            break;
        } catch (StaleElementReferenceException e) {
            if (timer.getElapsedSeconds() >= 20) {
                debug("getAttribute is borked, throwing up...");
                throw e;
            } else {
                debug("getAttribute failed again but we're still trying after " + timer.getElapsedMilliseconds() + " milliseconds.");
            }
        }
    }

上面的设计是为了在抛出 StaleElementReferenceException 的情况下继续尝试 find/getAttribute 组合,直到 findElement 调用通常超时(隐式超时 20 秒)。运行它的结果是 findElement 调用成功,然后 getAttribute 调用在整整 20 秒内每隔 50 毫秒左右抛出一个 StaleElementReferenceException ;然后它倾倒了。在此期间,页面上没有发生任何事情,至少我看不到。

关于 WebElement 在这种情况下为何或如何变得陈旧的任何想法?

编辑:我找到了一种解决方法,仅适用于您尝试仅从页面获取数据的情况(即,从页面获取属性或文本,而不是单击或发送击键)。我的代码已经使用了一个名为 JSoup 的库来将 DOM 读入内存,如果您需要导航 DOM 并查找信息但又想避免对 DOM 本身进行一系列低性能的 Selenium 查找操作,这将非常方便。使用 JSoup,我能够读取 DOM 的静态版本并提取我寻找的信息。但是,如果我发现自己处于想要单击或发送密钥的情况下,这种解决方法将毫无用处,所以我仍然想知道是否还有其他选择。

【问题讨论】:

  • 如果元素是陈旧的,那么反复尝试使用 findElement() 不会有太大帮助。这个&lt;object&gt; 看起来如何在视频开始播放之前?您可以通过 Selenium 访问它而不会收到 StaleElementReferenceException 吗?
  • @Dominik 我不确定你的意思。我尝试反复调用 findElement().getAttribute()。 findElement() 不会导致错误, getAttribute() 会。 findElement 本质上获得了 WebElement 的“新”版本,该版本应该在那个时间点与 DOM 匹配。我的希望是,通过在一段时间内反复调用它,我会遇到 DOM 没有改变的时刻(假设确实如此),因此 getAttribute() 调用会成功,因为 WebElement 仍然是“新鲜的” " 当 getAttribute() 被调用时。
  • @Dominik 至于 标签,它不会从页面加载时发生变化。据我所见,在视频播放之前、期间或之后,页面源中的任何内容都没有变化。无论如何,我直到视频结束后才调用 findElement().getAttribute(),因此当 StaleElementReferenceExceptions 被抛出时,屏幕或页面源中什么都没有发生。至少我没有发现任何东西。
  • 查看您的代码,我也没有发现任何明显错误。我不确定您的 CSS 定位器是否正确……那么尝试其他一些选项怎么样。例如 By.name("flashvars")...

标签: selenium webdriver


【解决方案1】:

StaleElementReferenceException 是由您的代码试图定位 DOM 中不再存在的内容引起的。如果您使用 JSoup 访问旧的静态版本的 DOM,则 Flash 视频结束后的 DOM 内容可能不再包含 flashvars 参数和/或其值属性。使用最快的代码选项,您的初始方法是正确的:

  String text = driver.findElement(By.cssSelector("object#flashContentparam[name='flashvars']")).getAttribute("value");

在视频结束后等待一个元素出现在 DOM 中,表明视频已经结束,然后尝试查找 flashvars 参数及其 value 属性。 P.S.:StaleElementReferenceException 很少是由快速完整或部分 (AJAX) 页面刷新 (

【讨论】:

    猜你喜欢
    • 2011-06-18
    • 2014-11-15
    • 1970-01-01
    • 2015-11-14
    • 2012-04-24
    • 1970-01-01
    • 2014-03-03
    • 1970-01-01
    • 2018-09-14
    相关资源
    最近更新 更多