Selenium 在调用 FindElements 后停止工作
Selenium stops to work after call FindElements
有时当我调用 Selenium FindElements(By) 时,它会抛出异常并且我的驱动程序停止工作。参数 "BY" 可能是问题所在:当我使用不同的 by 搜索相同的元素时,它起作用了。
我还可以看到,即使我的元素存在,或者如果它之前调用了具有相同参数的相同方法,它也不会阻止该方法抛出异常。
我的方法是:
public IWebElement SafeFindElement(By by)
{
try
{
IWebElement element;
if (_driver.FindElements(by).Any())
{
element = _driver.FindElements(by).First();
return element;
}
return null;
}
catch (NoSuchElementException)
{
return null;
}
catch (Exception)
{
return null;
}
}
一个 BY 值的例子,不是一直有效(即使它存在于页面中):
By.CssSelector("input[data-id-selenium='entrar']")
异常:
WebDriverException
The HTTP request to the remote WebDriver server for URL
http://localhost:46432/session/ef6cd2f1bf3ed5c924fe29d0f2c677cf/elements
timed out after 60 seconds.
我不知道它可能是什么或导致这种不稳定的原因。有人有什么建议吗?
@EDIT
我找到了一个临时解决方案。
早些时候,我尝试使用以下方法查找元素:
var element = browser
.FindElements(By.CssSelector("input[data-id-selenium='entrar']")
.FirstOrDefault();
或
var element = browser
.FindElements(By.XPath("//input[@data-id-selenium='entrar']");
.FirstOrDefault();
现在,我正在使用:
var element = browser
.FindElements(By.TagName("input"))
.FirstOrDefault(x => x.GetAttribute("data-id-selenium") == "entrar");
他们做同样的事情,但第一个无故抛出异常。此外,这是一个临时解决方案,我正在尝试解决仅使用选择器搜索元素的问题。
这是 selenium 的一个已知问题,webdriver 服务器对每个请求的最大超时限制为 60 秒,我不知道有什么方法可以更改它,我建议您考虑使用在使用 FindElement() 之前显式等待,虽然这个问题可能会发生,但有一个解决这个问题的方法对我有用,使用我已经实现的扩展方法,这个想法是等待特定条件,这样如果 webdriver 抛出异常这表示它已经等待了 60 秒的最大限制,您可以通过尝试在特定时间段内重复等待特定条件来处理这个问题,每次循环都会向 webdriver 服务器发送一个新请求。
public static void WaitUntil(this IWebDriver webDriver, Func<IWebDriver, bool> predicate, TimeSpan timeout)
{
var dtStart = DateTime.Now;
while (true)
{
try
{
if (!predicate(webDriver))
throw new Exception();
break;
}
catch (Exception ex)
{
if (DateTime.Now.Subtract(dtStart) >= timeout)
throw ex;
}
Thread.Sleep(30000);
}
}
public static void WaitUntil(this IWebDriver webDriver, Func<IWebDriver, IWebElement> predicate, TimeSpan timeout)
{
var dtStart = DateTime.Now;
while (true)
{
try
{
predicate(webDriver);
break;
}
catch (Exception ex)
{
if (DateTime.Now.Subtract(dtStart) >= timeout)
throw ex;
}
Thread.Sleep(30000);
}
}
例如,您可以使用这样的扩展方法
webDriver.WaitUntil(w => w.Title == "title", TimeSpan.FromMinutes(2));
或
webDriver.WaitUntil(ExpectedConditions.TitleIs("title"), TimeSpan.FromMinutes(2));
或
webDriver.WaitUntil(ExpectedConditions.ElementIsVisible(By.Id("elementId")), TimeSpan.FromMinutes(2));
更新
查看您的上一条评论后,您说您在使用 FindElements(By.TagName("input"); 时得到了一些元素,这意味着您使用的选择器导致了问题,您可以按标签名称查找元素,然后按属性值过滤结果,或者如果您确定您使用的选择器是正确的并且行为不正确,请尝试调试问题,如果有 javascript负责设置属性值的那个,确保它在调用 FindElement() 之前先使用隐式或显式等待运行。
我发现了问题。我在我的所有测试服中都使用了一种方法来等待加载消息消失。但它尝试使用 jquery,但并非我应用程序中的所有页面都使用它。
所以,selenium 放弃尝试在 60 秒后执行 jquery 和 returns 超时错误,但这个错误并没有破坏 Selenium 驱动程序,只有 FindElements 然后它 return这是一个空列表。当它尝试 return 空列表时,所有驱动器都坏了。
原方法:
public void WaitLoadingMessage(int timeout)
{
while (timeout > 0)
{
try
{
var loadingIsVisible = _js.ExecuteScript("return $('#loading-geral').is(':visible');").ToString();
if (loadingIsVisible.ToLower() == "false")
break;
Thread.Sleep(1000);
timeout -= 1000;
}
catch (Exception ex)
{
if (!ex.Message.ToLower().Contains("$ is not defined"))
throw;
}
}
}
更正:
public void WaitLoadingMessage(int timeout)
{
while (timeout > 0)
{
try
{
var loadingIsVisible = _js.ExecuteScript("return $('#loading-geral').is(':visible');").ToString();
if (loadingIsVisible.ToLower() == "false")
break;
Thread.Sleep(1000);
timeout -= 1000;
}
catch (Exception ex)
{
if (!ex.Message.ToLower().Contains("$ is not defined"))
throw;
break;
}
}
}
有时当我调用 Selenium FindElements(By) 时,它会抛出异常并且我的驱动程序停止工作。参数 "BY" 可能是问题所在:当我使用不同的 by 搜索相同的元素时,它起作用了。
我还可以看到,即使我的元素存在,或者如果它之前调用了具有相同参数的相同方法,它也不会阻止该方法抛出异常。
我的方法是:
public IWebElement SafeFindElement(By by)
{
try
{
IWebElement element;
if (_driver.FindElements(by).Any())
{
element = _driver.FindElements(by).First();
return element;
}
return null;
}
catch (NoSuchElementException)
{
return null;
}
catch (Exception)
{
return null;
}
}
一个 BY 值的例子,不是一直有效(即使它存在于页面中):
By.CssSelector("input[data-id-selenium='entrar']")
异常:
WebDriverException
The HTTP request to the remote WebDriver server for URL http://localhost:46432/session/ef6cd2f1bf3ed5c924fe29d0f2c677cf/elements timed out after 60 seconds.
我不知道它可能是什么或导致这种不稳定的原因。有人有什么建议吗?
@EDIT
我找到了一个临时解决方案。
早些时候,我尝试使用以下方法查找元素:
var element = browser
.FindElements(By.CssSelector("input[data-id-selenium='entrar']")
.FirstOrDefault();
或
var element = browser
.FindElements(By.XPath("//input[@data-id-selenium='entrar']");
.FirstOrDefault();
现在,我正在使用:
var element = browser
.FindElements(By.TagName("input"))
.FirstOrDefault(x => x.GetAttribute("data-id-selenium") == "entrar");
他们做同样的事情,但第一个无故抛出异常。此外,这是一个临时解决方案,我正在尝试解决仅使用选择器搜索元素的问题。
这是 selenium 的一个已知问题,webdriver 服务器对每个请求的最大超时限制为 60 秒,我不知道有什么方法可以更改它,我建议您考虑使用在使用 FindElement() 之前显式等待,虽然这个问题可能会发生,但有一个解决这个问题的方法对我有用,使用我已经实现的扩展方法,这个想法是等待特定条件,这样如果 webdriver 抛出异常这表示它已经等待了 60 秒的最大限制,您可以通过尝试在特定时间段内重复等待特定条件来处理这个问题,每次循环都会向 webdriver 服务器发送一个新请求。
public static void WaitUntil(this IWebDriver webDriver, Func<IWebDriver, bool> predicate, TimeSpan timeout)
{
var dtStart = DateTime.Now;
while (true)
{
try
{
if (!predicate(webDriver))
throw new Exception();
break;
}
catch (Exception ex)
{
if (DateTime.Now.Subtract(dtStart) >= timeout)
throw ex;
}
Thread.Sleep(30000);
}
}
public static void WaitUntil(this IWebDriver webDriver, Func<IWebDriver, IWebElement> predicate, TimeSpan timeout)
{
var dtStart = DateTime.Now;
while (true)
{
try
{
predicate(webDriver);
break;
}
catch (Exception ex)
{
if (DateTime.Now.Subtract(dtStart) >= timeout)
throw ex;
}
Thread.Sleep(30000);
}
}
例如,您可以使用这样的扩展方法
webDriver.WaitUntil(w => w.Title == "title", TimeSpan.FromMinutes(2));
或
webDriver.WaitUntil(ExpectedConditions.TitleIs("title"), TimeSpan.FromMinutes(2));
或
webDriver.WaitUntil(ExpectedConditions.ElementIsVisible(By.Id("elementId")), TimeSpan.FromMinutes(2));
更新
查看您的上一条评论后,您说您在使用 FindElements(By.TagName("input"); 时得到了一些元素,这意味着您使用的选择器导致了问题,您可以按标签名称查找元素,然后按属性值过滤结果,或者如果您确定您使用的选择器是正确的并且行为不正确,请尝试调试问题,如果有 javascript负责设置属性值的那个,确保它在调用 FindElement() 之前先使用隐式或显式等待运行。
我发现了问题。我在我的所有测试服中都使用了一种方法来等待加载消息消失。但它尝试使用 jquery,但并非我应用程序中的所有页面都使用它。
所以,selenium 放弃尝试在 60 秒后执行 jquery 和 returns 超时错误,但这个错误并没有破坏 Selenium 驱动程序,只有 FindElements 然后它 return这是一个空列表。当它尝试 return 空列表时,所有驱动器都坏了。
原方法:
public void WaitLoadingMessage(int timeout)
{
while (timeout > 0)
{
try
{
var loadingIsVisible = _js.ExecuteScript("return $('#loading-geral').is(':visible');").ToString();
if (loadingIsVisible.ToLower() == "false")
break;
Thread.Sleep(1000);
timeout -= 1000;
}
catch (Exception ex)
{
if (!ex.Message.ToLower().Contains("$ is not defined"))
throw;
}
}
}
更正:
public void WaitLoadingMessage(int timeout)
{
while (timeout > 0)
{
try
{
var loadingIsVisible = _js.ExecuteScript("return $('#loading-geral').is(':visible');").ToString();
if (loadingIsVisible.ToLower() == "false")
break;
Thread.Sleep(1000);
timeout -= 1000;
}
catch (Exception ex)
{
if (!ex.Message.ToLower().Contains("$ is not defined"))
throw;
break;
}
}
}