【发布时间】: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() 不会有太大帮助。这个
<object>看起来如何在视频开始播放之前?您可以通过 Selenium 访问它而不会收到 StaleElementReferenceException 吗? -
@Dominik 我不确定你的意思。我尝试反复调用 findElement().getAttribute()。 findElement() 不会导致错误, getAttribute() 会。 findElement 本质上获得了 WebElement 的“新”版本,该版本应该在那个时间点与 DOM 匹配。我的希望是,通过在一段时间内反复调用它,我会遇到 DOM 没有改变的时刻(假设确实如此),因此 getAttribute() 调用会成功,因为 WebElement 仍然是“新鲜的” " 当 getAttribute() 被调用时。
-
@Dominik 至于
-
查看您的代码,我也没有发现任何明显错误。我不确定您的 CSS 定位器是否正确……那么尝试其他一些选项怎么样。例如 By.name("flashvars")...