我正在试用Internet Explorer中最初针对Chrome开发的一些脚本(并且在那里工作得很好),并且发现StaleElementReferenceExceptions似乎是常态。显然这是因为IE速度慢得多?
我的理解是,当您找到WebElement,然后DOM发生更改,然后您尝试对该WebElement执行某些操作时会发生这些异常,这会混淆Selenium,因为页面现在已更改且WebElement中的引用为no更长的有效。如果这就是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 param的值,所以我有以下代码:
text = driver.findElement(By.cssSelector("object#flashContent param[name='flashvars']")).getAttribute("value");
所以我不能减少找到param WebElement和获取它的属性之间的时间,而不是我已经拥有它,但似乎getAttribute每次都抛出一个StaleElementReferenceException。我打开了页面源并观看了窗口 - 据我所见,没有任何变化。我尝试在一段时间内捕获Exception并且只是重试,希望我能在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.");
}
}
}
以上内容旨在继续尝试find / getAttribute组合,即使抛出了StaleElementReferenceException,直到findElement调用通常超时(隐式超时为20秒)。运行它的结果是findElement调用成功,然后getAttribute调用每50毫秒左右抛出一个StaleElementReferenceException整整20秒;然后它就抛弃了。在这段时间里,页面上没有任何事情发生,至少不是我能看到的。
关于WebElement在这种情况下为何或如何陈旧的任何想法?
编辑:我找到了一种解决方法,仅适用于您尝试从页面获取数据的情况(即,从页面获取属性或文本而不是单击或发送击键)。我的代码已经使用了一个名为JSoup的库来将DOM读入内存,如果你需要导航DOM并查找信息但是想避免在DOM本身上进行一系列低性能的Selenium查找操作,这非常方便。使用JSoup我能够读取DOM的静态版本并提取我所寻求的信息。但是,如果我发现自己处于想要点击或发送密钥的情况,这种解决方法将毫无用处,所以我仍然想知道是否还有其他选择。
答案 0 :(得分:0)
StaleElementReferenceException是由您的代码尝试查找DOM中不再存在的内容引起的。如果您使用JSoup访问旧的静态DOM版本,则Flash视频结束后DOM的内容可能不再包含flashvars参数和/或其value属性。使用最快的代码选项,您的初始方法是正确的:
String text = driver.findElement(By.cssSelector("object#flashContentparam[name='flashvars']")).getAttribute("value");
在视频结束后,等待元素出现在DOM中,表示视频已完成,然后尝试查找flashvars参数及其value属性。 P.S。:很少StaleElementReferenceException是由快速完全或部分(AJAX)页面刷新(<500毫秒)引起的,通常它是算法问题。