Wait for page load in Selenium

后端 未结 30 2507
攒了一身酷
攒了一身酷 2020-11-22 07:12

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

30条回答
  •  一生所求
    2020-11-22 07:58

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

提交回复
热议问题