Wait until page is loaded with Selenium WebDriver for Python
The webdriver
will wait for a page to load by default via .get()
method.
As you may be looking for some specific element as @user227215 said, you should use WebDriverWait
to wait for an element located in your page:
from selenium import webdriverfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import Byfrom selenium.common.exceptions import TimeoutExceptionbrowser = webdriver.Firefox()browser.get("url")delay = 3 # secondstry: myElem = WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'IdOfMyElement'))) print "Page is ready!"except TimeoutException: print "Loading took too much time!"
I have used it for checking alerts. You can use any other type methods to find the locator.
EDIT 1:
I should mention that the webdriver
will wait for a page to load by default. It does not wait for loading inside frames or for ajax requests. It means when you use .get('url')
, your browser will wait until the page is completely loaded and then go to the next command in the code. But when you are posting an ajax request, webdriver
does not wait and it's your responsibility to wait an appropriate amount of time for the page or a part of page to load; so there is a module named expected_conditions
.
Trying to pass find_element_by_id
to the constructor for presence_of_element_located
(as shown in the accepted answer) caused NoSuchElementException
to be raised. I had to use the syntax in fragles' comment:
from selenium import webdriverfrom selenium.common.exceptions import TimeoutExceptionfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import Bydriver = webdriver.Firefox()driver.get('url')timeout = 5try: element_present = EC.presence_of_element_located((By.ID, 'element_id')) WebDriverWait(driver, timeout).until(element_present)except TimeoutException: print "Timed out waiting for page to load"
This matches the example in the documentation. Here is a link to the documentation for By.
Find below 3 methods:
readyState
Checking page readyState (not reliable):
def page_has_loaded(self): self.log.info("Checking if {} page is loaded.".format(self.driver.current_url)) page_state = self.driver.execute_script('return document.readyState;') return page_state == 'complete'
The
wait_for
helper function is good, but unfortunatelyclick_through_to_new_page
is open to the race condition where we manage to execute the script in the old page, before the browser has started processing the click, andpage_has_loaded
just returns true straight away.
id
Comparing new page ids with the old one:
def page_has_loaded_id(self): self.log.info("Checking if {} page is loaded.".format(self.driver.current_url)) try: new_page = browser.find_element_by_tag_name('html') return new_page.id != old_page.id except NoSuchElementException: return False
It's possible that comparing ids is not as effective as waiting for stale reference exceptions.
staleness_of
Using staleness_of
method:
@contextlib.contextmanagerdef wait_for_page_load(self, timeout=10): self.log.debug("Waiting for page to load at {}.".format(self.driver.current_url)) old_page = self.find_element_by_tag_name('html') yield WebDriverWait(self, timeout).until(staleness_of(old_page))
For more details, check Harry's blog.