我正在寻找一个简单的方法,重复一个方法,当一个元素(选择器),例如一个网页上的按钮无法找到。
我的想法或计划是:
- 如果可以找到选择器,则该方法已完成
- 如果选择器不能当被找到时,它应该重复"FindElement"方法最多可达3倍
- 如果选择器不能被发现后,第三次尝试,应该给我一个输出消息的"NoSuchElementException e"
我尝试了不同的循环,我总是以无尽的循环结束,就像下面的代码一样。
public static void FindElement(IWebDriver webDriver, string selector)
{
int maxTries = 0;
try
{
webDriver.FindElement(By.XPath(selector));
Console.WriteLine("Element found.");
}
catch (NoSuchElementException e)
{
if (maxTries !> 3 )
{
Console.WriteLine("Element, not found. Retrying.");
maxTries++;
FindElement(webDriver, selector);
}
else
{
Console.WriteLine(e);
}
}
}
真是巧合:就在几天前,我写了一个简短的助手方法来分离"重试逻辑"。源自"商业逻辑">
private T Retry<T>(Func<T> action, int maxRetryCount, int waitMilliseconds,
Func<Exception, bool> retryCondition)
{
var retryCount = 0;
while (true)
{
try
{
// If the action was successful (no exception thrown),
// we can leave the method.
return action();
}
catch (Exception ex) when (retryCount < maxRetryCount && retryCondition(ex))
{
retryCount += 1;
Thread.Sleep(waitMilliseconds);
}
}
}
在你的例子中,它的调用方式如下:
var element = Retry(() => webDriver.FindElement(By.XPath(selector)),
2, 0,
ex => ex is NoSuchElementException);
每当达到最大重试次数时,异常不再被捕获(when
条件失败),而可以由常规异常处理逻辑捕获。
既然你正在尝试自动化web浏览器,你可以考虑传递0
以外的东西作为waitMilliseconds
,给浏览器时间来渲染仍然缺失的元素。
为什么不把maxTry
放在函数之外呢?
int maxTry=3;
string errorMessage="";
for(int i=0;i<maxTry;i++)
{
try
{
FindElement(webDriver,selector)
errorMessage="";
break;
}
catch (NoSuchElementException e)
{
errorMessage=e;
}
}
if(errorMessage!="")
{
Console.WriteLine(e);
}
else
{
Console.WriteLine("Element found.");
}
对于递归,您应该将剩余迭代的数量传递给函数,并在每次迭代中减少它。
public static void FindElement(IWebDriver webDriver, string selector, int iterations = 3)
{
iterations--;
if (iterations < 0)
{
Console.WriteLine("Max iterations passed, exiting")
return;
}
try
{
webDriver.FindElement(By.XPath(selector));
Console.WriteLine("Element found.");
}
catch (NoSuchElementException e)
{
Console.WriteLine("Element not found. Retrying.");
FindElement(webDriver, selector, iterations);
}
}