如何让Selenium 2.0等待页面加载?


当前回答

您可以尝试这段代码,让页面完全加载,直到找到元素为止。

public void waitForBrowserToLoadCompletely() {
    String state = null;
    String oldstate = null;
    try {
        System.out.print("Waiting for browser loading to complete");

        int i = 0;
        while (i < 5) {
            Thread.sleep(1000);
            state = ((JavascriptExecutor) driver).executeScript("return document.readyState;").toString();
            System.out.print("." + Character.toUpperCase(state.charAt(0)) + ".");
            if (state.equals("interactive") || state.equals("loading"))
                break;
            /*
             * If browser in 'complete' state since last X seconds. Return.
             */

            if (i == 1 && state.equals("complete")) {
                System.out.println();
                return;
            }
            i++;
        }
        i = 0;
        oldstate = null;
        Thread.sleep(2000);

        /*
         * Now wait for state to become complete
         */
        while (true) {
            state = ((JavascriptExecutor) driver).executeScript("return document.readyState;").toString();
            System.out.print("." + state.charAt(0) + ".");
            if (state.equals("complete"))
                break;

            if (state.equals(oldstate))
                i++;
            else
                i = 0;
            /*
             * If browser state is same (loading/interactive) since last 60
             * secs. Refresh the page.
             */
            if (i == 15 && state.equals("loading")) {
                System.out.println("\nBrowser in " + state + " state since last 60 secs. So refreshing browser.");
                driver.navigate().refresh();
                System.out.print("Waiting for browser loading to complete");
                i = 0;
            } else if (i == 6 && state.equals("interactive")) {
                System.out.println(
                        "\nBrowser in " + state + " state since last 30 secs. So starting with execution.");
                return;
            }

            Thread.sleep(4000);
            oldstate = state;

        }
        System.out.println();

    } catch (InterruptedException ie) {
        ie.printStackTrace();
    }
}

其他回答

这段代码将等待页面上的所有元素都加载到DOM中。

WebDriver driver = new WebDriver();
WebDriverWait wait = new WebDriverWait(driver, timeout);

wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("//*")));

你可以使用等待。硒中基本上有两种类型的等待

隐式等 显式等

-隐式等待

这很简单,请参阅下面的语法:

driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);

-显式等待

在此等待中显式等待或有条件等待,直到给定条件发生。

WebDriverWait wait = new WebDriverWait(driver, 40);
WebElement element = wait.until(ExpectedConditions.elementToBeClickable(By.id("someid")));

您可以使用其他属性,如visblityOf(), visblityOfElement()

如果你设置了驱动程序的隐式等待,然后调用findElement方法在你期望加载页面上的元素上,WebDriver将轮询该元素,直到找到该元素或达到超时值。

driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);

来源:implicit-waits

使用类WebDriverWait

也可以看这里

您可以期望显示一些元素。类似于c#:

WebDriver _driver = new WebDriver();
WebDriverWait _wait = new WebDriverWait(_driver, new TimeSpan(0, 1, 0));

_wait.Until(d => d.FindElement(By.Id("Id_Your_UIElement")));

所有这些解决方案在特定情况下都是可行的,但它们至少会遇到以下几个问题中的一个:

它们不够通用——它们想让你提前知道,你要访问的页面的某些特定条件将是真的(例如某些元素将被显示)。 它们会出现竞态条件,即您使用的元素实际上同时出现在旧页面和新页面上。

下面是我尝试的避免这个问题的通用解决方案(在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__))

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

假设你想点击一个文本为“my link”的链接,例如:

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)

对于更多python化的、可重用的、通用的helper,你可以创建一个上下文管理器:

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)

然后你可以在几乎任何硒相互作用中使用它:

with wait_for_page_load(browser):
    browser.find_element_by_link_text('my link').click()

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

更多信息在这里关于它的博客文章