Selenium等到文档准备好了

Gir*_*ish 124 selenium load document wait

任何人都可以让我如何让硒等到页面完全加载的时候?我想要一些通用的东西,我知道我可以配置WebDriverWait并调用类似'find'的东西让它等待,但我不会那么远.我只需要测试页面加载成功并转到下一页进行测试.

我在.net中找到了一些东西但是无法在java中使用它...

IWait<IWebDriver> wait = new OpenQA.Selenium.Support.UI.WebDriverWait(driver, TimeSpan.FromSeconds(30.00));
wait.Until(driver1 => ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete"));
Run Code Online (Sandbox Code Playgroud)

有人想过吗?

Pet*_*ček 84

您建议的解决方案只等待DOMreadyState发出信号complete.但Selenium默认尝试通过driver.get()element.click()方法等待页面加载的那些(以及更多一点).他们已经阻止,他们等待页面完全加载,那些应该正常工作.

显然,问题是通过AJAX请求和运行脚本重定向 - 这些不能被Selenium捕获,它不会等待它们完成.此外,您无法通过readyState它可靠地捕获它们- 它等待一点,这可能很有用,但它会complete在下载所有AJAX内容之前发出信号.

没有通用的解决方案可以在任何地方和每个人工作,这就是为什么它很难,每个人都使用一些不同的东西.

一般规则是依靠WebDriver来完成他的工作,然后使用隐式等待,然后使用显式等待你想在页面上断言的元素,但是还有更多的技术可以完成.您应该在测试页面上选择最适合您情况的一个(或其中几个组合).

有关详细信息,请参阅我的两个答案:

  • 这是不准确的,Selenium不会等待或阻止`element.click()`调用. (19认同)
  • 比较一些[我在邮件列表上的对话](https://groups.google.com/forum/#!topic/selenium-developers/hA_jTx4vrDM),这似乎是不准确的.selenium可能会阻止你明确请求URL的.get调用,但它对点击调用没有任何特别之处,因为它无法判断你是否点击了"真实"超链接或者是否会被javascript拦截. .. (5认同)
  • 我在邮件列表讨论开始时链接到一个错误.甚至文档也不明确:*"如果click()[...]通过发送本机事件来完成,那么该方法将\*not\*wait"* (4认同)
  • 所以这一切都取决于浏览器是否使用"本机事件".默认情况下,似乎大多数人都会这样做:https://code.google.com/p/selenium/wiki/AdvancedUserInteractions#Native_events_versus_synthetic_events(所以我说这些文档充其量是误导性的.会ping邮件列表) . (4认同)
  • @hwjp需要详细说明吗?[JavaDocs另有说法](https://selenium.googlecode.com/git/docs/api/java/org/openqa/selenium/WebElement.html#click%28%29):_"如果这会导致新的页面要加载,此方法将尝试阻止,直到页面加载."_ (3认同)

Man*_*dan 79

试试这段代码:

  driver.manage().timeouts().pageLoadTimeout(10, TimeUnit.SECONDS);
Run Code Online (Sandbox Code Playgroud)

上面的代码将等待最多10秒的页面加载.如果页面加载超过它将抛出的时间TimeoutException.你抓住了例外,满足了你的需求.我不确定是否在抛出异常后退出页面加载.我还没有尝试这个代码.想要尝试一下.

这是一个隐含的等待.如果你设置了一次它将具有范围,直到Web驱动程序实例销毁.

有关更多信息.

  • 此方法的问题在于,即使隐式等待先前成功返回了WebElement对象,也可能无法完全访问DOM.然后,如果您尝试单击该元素,您将获得陈旧元素异常.所以,这个答案并不完全安全. (18认同)
  • 谢谢,所以如果页面在10秒之前加载会发生什么,它还会等待10秒后加载后执行下一行吗? (3认同)
  • 这用于当您希望页面加载花费太长时间来超时并抛出异常时,它不会立即等待页面加载或设置更好的加载策略.它默认为无限时间,因此您的页面加载永远不会抛出异常,Selenium总是会尝试等待它们完全加载. (3认同)
  • 这个超时与等待文档加载有什么关系? (3认同)

小智 60

这是您给出的示例的可用Java版本:

void waitForLoad(WebDriver driver) {
    new WebDriverWait(driver, 30).until((ExpectedCondition<Boolean>) wd ->
            ((JavascriptExecutor) wd).executeScript("return document.readyState").equals("complete"));
}
Run Code Online (Sandbox Code Playgroud)

示例对于c#:

public static void WaitForLoad(IWebDriver driver, int timeoutSec = 15)
{
  IJavaScriptExecutor js = (IJavaScriptExecutor)driver;
  WebDriverWait wait = new WebDriverWait(driver, new TimeSpan(0, 0, timeoutSec));
  wait.Until(wd => js.ExecuteScript("return document.readyState").ToString() == "complete");
}
Run Code Online (Sandbox Code Playgroud)

  • Java 1.7版本:wait.until(new Predicate <WebDriver>(){public boolean apply(WebDriver driver){return((JavascriptExecutor)driver).executeScript("return document.readyState").equals("complete");} }); (3认同)
  • 你可以把它放在java 1.7版本兼容,因为lambda表达式不支持 (2认同)

hwj*_*wjp 11

这是我在Python中尝试完全通用的解决方案:

首先,一个通用的"等待"函数(如果你愿意,可以使用WebDriverWait,我发现它们很难看):

def wait_for(condition_function):
    start_time = time.time()
    while time.time() < start_time + 3:
        if condition_function():
            return True
        else:
            time.sleep(0.1)
    raise Exception('Timeout waiting for {}'.format(condition_function.__name__))
Run Code Online (Sandbox Code Playgroud)

接下来,该解决方案依赖于selenium为页面上的所有元素(包括顶级元素)记录(内部)id号的事实<html>.当页面刷新或加载时,它会获得一个带有新ID的新html元素.

因此,假设您要单击带有文本"我的链接"的链接,例如:

old_page = browser.find_element_by_tag_name('html')

browser.find_element_by_link_text('my link').click()

def page_has_loaded():
    new_page = browser.find_element_by_tag_name('html')
    return new_page.id != old_page.id

wait_for(page_has_loaded)
Run Code Online (Sandbox Code Playgroud)

对于更多Pythonic,可重用的通用助手,您可以创建一个上下文管理器:

from contextlib import contextmanager

@contextmanager
def wait_for_page_load(browser):
    old_page = browser.find_element_by_tag_name('html')

    yield

    def page_has_loaded():
        new_page = browser.find_element_by_tag_name('html')
        return new_page.id != old_page.id

    wait_for(page_has_loaded)
Run Code Online (Sandbox Code Playgroud)

然后你可以在任何硒交互中使用它:

with wait_for_page_load(browser):
    browser.find_element_by_link_text('my link').click()
Run Code Online (Sandbox Code Playgroud)

我认为那是防弹的!你怎么看?

关于它博客文章中的更多信息


Rub*_*nov 7

我遇到了类似的问题.我需要等到我的文档准备就绪,直到所有Ajax调用完成.事实证明第二个条件很难被发现.最后,我检查了活动的Ajax调用,并且它工作正常.

使用Javascript:

return (document.readyState == 'complete' && jQuery.active == 0)
Run Code Online (Sandbox Code Playgroud)

完整的C#方法:

private void WaitUntilDocumentIsReady(TimeSpan timeout)
{
    var javaScriptExecutor = WebDriver as IJavaScriptExecutor;
    var wait = new WebDriverWait(WebDriver, timeout);            

    // Check if document is ready
    Func<IWebDriver, bool> readyCondition = webDriver => javaScriptExecutor
        .ExecuteScript("return (document.readyState == 'complete' && jQuery.active == 0)");
    wait.Until(readyCondition);
}
Run Code Online (Sandbox Code Playgroud)


小智 6

WebDriverWait wait = new WebDriverWait(dr, 30);
wait.until(ExpectedConditions.jsReturnsValue("return document.readyState==\"complete\";"));
Run Code Online (Sandbox Code Playgroud)