Wait for page load in Selenium

2018-12-31 15:29发布

How do you make Selenium 2.0 wait for the page to load?

30条回答
看淡一切
2楼-- · 2018-12-31 15:50

All of these solutions are OK for specific cases, but they suffer from at least one of a couple of possible problems:

  1. They are not generic enough -- they want you to know, ahead of time, that some specific condition will be true of the page you are going to (eg some element will be displayed)

  2. They are open to a race condition where you use an element that is actually present on the old page as well as the new page.

Here's my attempt at a generic solution that avoids this problem (in Python):

First, a generic "wait" function (use a WebDriverWait if you like, I find them ugly):

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__))

Next, the solution relies on the fact that selenium records an (internal) id-number for all elements on a page, including the top-level <html> element. When a page refreshes or loads, it gets a new html element with a new ID.

So, assuming you want to click on a link with text "my link" for example:

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)

For more Pythonic, reusable, generic helper, you can make a context manager:

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)

And then you can use it on pretty much any selenium interaction:

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

I reckon that's bulletproof! What do you think?

More info in a blog post about it here

查看更多
千与千寻千般痛.
3楼-- · 2018-12-31 15:51

If you set the implicit wait of the driver, then call the findElement method on an element you expect to be on the loaded page, the WebDriver will poll for that element until it finds the element or reaches the time out value.

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

source: implicit-waits

查看更多
孤独总比滥情好
4楼-- · 2018-12-31 15:51

You can try this code to let the page load completely until element is found.

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();
    }
}
查看更多
何处买醉
5楼-- · 2018-12-31 15:52

You can use the below existing method to set the time for pageeLoadTimeout in below example if the page is taking more than 20 seconds to load , then it will throw an exception of page reload

 WebDriver driver = new FirefoxDriver();
driver.manage().timeouts().pageLoadTimeout(20, TimeUnit.SECONDS)
查看更多
孤独寂梦人
6楼-- · 2018-12-31 15:52

You can use wait. there are basically 2 types of wait in selenium

  • Implicit wait
  • Explicit wait

- Implicit wait

This is very simple please see syntax below:

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

- Explicit wait

Explicitly wait or conditional wait in this wait until given condition is occurred.

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

You can use other properties like visblityOf(), visblityOfElement()

查看更多
妖精总统
7楼-- · 2018-12-31 15:52

How to get Selenium to wait for page load after a click provides the following interesting approach:

  1. Store a reference to a WebElement from the old page.
  2. Click the link.
  3. Keep on invoking operations on the WebElement until StaleElementReferenceException is thrown.

Sample code:

WebElement link = ...;
link.click();
new WebDriverWait(webDriver, timeout).until((org.openqa.selenium.WebDriver input) ->
{
    try
    {
        link.isDisplayed();
        return false;
    }
    catch (StaleElementReferenceException unused)
    {
        return true;
    }
});
查看更多
登录 后发表回答