2

我正在 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 的静态版本并提取我寻找的信息。但是,如果我发现自己处于想要单击或发送密钥的情况下,这种解决方法将毫无用处,所以我仍然想知道是否还有其他选择。

4

1 回答 1

0

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

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

等待视频结束后 DOM 中出现指示视频已结束的元素,然后尝试查找 flashvars 参数及其 value 属性。PS:StaleElementReferenceException 很少是由快速完整或部分 (AJAX) 页面刷新(<500 ms)引起的,通常是算法问题。

于 2015-07-01T21:40:09.420 回答