Selenium - 过时的元素参考:元素未附加到页面
Posted
技术标签:
【中文标题】Selenium - 过时的元素参考:元素未附加到页面【英文标题】:Selenium - stale element reference: element is not attached to the page 【发布时间】:2017-12-13 14:17:29 【问题描述】:我试图了解为什么在我尝试显示从网站获取的项目时它会出错。 我也在使用 google chrome 作为浏览器。
chromeDriver.Navigate().GoToUrl("somewebsites");
chromeDriver.FindElement(By.Id("something.link.text")).Click();
chromeDriver.Manage().Timeouts().ImplicitlyWait(TimeSpan.FromSeconds(5));
还有我的代码的其他部分
var item = chromeDriver.FindElementsByXPath("//*[starts-with(@id,\"g_1_\")]/td[3]/span");
foreach (var value in item)
Console.WriteLine(value.Text);
每当我使用 "chromeDriver.FindElement(By.Id("something.link.text")).Click();" 时,它都会出错。我无法显示我提取的数据。
在错误消息中,它显示“OpenQA.Selenium.StaleElementReferenceException: 'stale element reference: element is not attach to the page document”。我检查了其他帖子,但我没有弄清楚。我该如何解决?
正如我所读到的,selenium 的响应速度比网站打开时间快得多,因此会出现错误。此外,它很少给出硒无法定位的元素。有什么建议吗?
编辑:如果我从显示功能中删除“.text”,它会显示“OpenQA.Selenium.Remote.RemoteWebElement”。字符串有问题吗?
EDIT2:我可以像这样保存从网站获取的数据:
[i]="System.Collections.ObjectModel.ReadOnlyCollection`1[OpenQA.Selenium.IWebElement]" 为此,我写了这样的东西:
string[] test= new string[100];
for (int i = 0; i < 100; i++)
kaan[i] = driver.FindElements(By.XPath("//*[starts-with(@id,\"g_1_\")]/td[3]/span")).ToString();
如何转换成文字
【问题讨论】:
StaleElementReference Exception in PageFactory的可能重复 请添加html。 【参考方案1】:我没有在 c# 中工作过,但在 java/selenium 上工作过。但是,我可以给你一个克服陈旧的想法。
通常,如果在启动 web 元素后元素属性或某些内容发生更改,我们将收到 Stale Exception。例如,在某些情况下,如果用户尝试单击同一页面上的同一元素,但在页面刷新后,会出现 staleelement 异常。
为了克服这个问题,我们可以创建新的 web 元素,以防页面发生更改或刷新。下面的代码可以给你一些想法。(它在java中,但概念是一样的)
例子:
webElement element = driver.findElement(by.xpath("//*[@id='***']"));
element.click();
//page is refreshed
element.click();//This will obviously throw stale exception
为了克服这个问题,我们可以将 xpath 存储在一些字符串中,并使用它创建一个新的 web 元素。
String xpath = "//*[@id='***']";
driver.findElement(by.xpath(xpath)).click();
//page has been refreshed. Now create a new element and work on it
driver.findElement(by.xpath(xpath)).click(); //This works
在这种情况下,我们正在收集一组 web 元素并迭代以获取文本。但是在收集 webelements 和 gettext 后,webelement 似乎有一些变化。我们可以使用循环并随时随地创建元素并获取文本。
for(int i = 0; i<5; i++)
String value = driver.findElement(by.xpath("//.....["+i+"]")).getText);
System.out.println(value);
希望这对您有所帮助。谢谢。
【讨论】:
它给出了一个想法,我会试试的。谢谢 这不起作用,因为 Selenium 缓存了选择器的结果。使用相同的选择器将给出相同的结果,因此返回初始的陈旧对象。 基本硒永远不会捕获。如果我们使用页面工厂,那么可能是。 @tocqueville 有没有办法处理选择器结果的缓存? Selenium 返回元素在 html 中已经改变(我插入time.sleep(10)
足以完成元素更改)。而且我没有将此元素分配给某个变量,而是在 python 中使用driver.find_element_by_xpath()
【参考方案2】:
我最初遇到了这个问题,但我通过一些技巧解决了它
等待某些父元素在页面中可见(可能是父容器 div) 等待任何 ajax (xhr) 请求围绕您尝试使用的元素完成 (这是诀窍)不要将任何元素存储为实例属性值,始终根据请求获取(这将帮助您摆脱陈旧的元素)。在 c# 6 中尝试表达式,示例 私有 IWebElement _parentContainer => _driver.FindElement(...)另外,您可以为 IWebElement 创建抽象的基本控件和一些扩展方法,并在查找元素时进行一些基本的检查操作
【讨论】:
【参考方案3】:这种类型的错误通常是由更新的 DOM 引起的。我建议您在所有包含 javascript/ajax 调用的页面上实际等待这些调用完成,然后再与站点交互。我通常在页面加载后立即执行此等待,并且在执行某种触发 javascript/ajax 调用和/或更新 DOM 的操作时。实际上,这意味着在页面加载(或与之交互)之后运行以下函数,然后找到您要与之交互的元素。
public void WaitForJqueryAjax()
int delay = MaxdelaySeconds;
while(delay > 0)
Thread.Sleep(1000);
var jquery = (bool)(this.driver as IJavaScriptExecutor)
.ExecuteScript("return window.jQuery == undefined");
if(jquery)
break;
var ajaxIsComplete = (bool)(this.driver as IJavaScriptExecutor)
.ExecuteScript("return window.jQuery.active == 0");
if(ajaxIsComplete)
break;
delay--;
【讨论】:
我也使用这个技巧。不过,如果 Ajax 调用不通过 jQuery,不知道该怎么做。【参考方案4】:我遇到过类似的情况。这里的主要问题是页面需要时间,所以我添加了 time.sleep(sec) 并且效果很好。
【讨论】:
一般来说,以这种方式依赖sleep()
最多只能为核心问题提供一种低效的解决方法。最好的情况是,它可能会等待太久,从而不必要地降低性能。最坏的情况是,它触发得太快,导致同样的问题。理想情况下,我们会绑定到一个特定的事件,以便在可用时触发它。您是否了解这里可能适合哪些事件,而不是简单地使用sleep()
来延迟处理?以上是关于Selenium - 过时的元素参考:元素未附加到页面的主要内容,如果未能解决你的问题,请参考以下文章
Selenium 如何解决滚动条问题,未显示元素不可操作问题
使用robot framework + selenium2 出现异常解决方法