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