Подождите, пока страница не будет загружена с Selenium WebDriver для Python
Я хочу очистить все данные страницы, реализованные с помощью бесконечной прокрутки. Следующий код python работает.
for i in range(100):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(5)
Это означает, что каждый раз, когда я прокручиваю вниз, мне нужно подождать 5 секунд, что обычно достаточно для завершения загрузки страницы вновь сгенерированного содержимого. Но, это не может быть эффективным во времени. Страница завершения загрузки нового содержимого в течение 5 секунд. Как я могу определить, закончила ли страница загрузку нового содержимого каждый раз, когда я прокручиваю вниз? Если я могу обнаружить это, я могу прокрутить вниз снова, чтобы увидеть больше содержимого, как только я знаю, что страница закончила загрузку. Это более эффективно.
8 ответов:
The
webdriverбудет ждать загрузки страницы по умолчанию через.get()метод.как вы можете искать какой-то конкретный элемент, как @user227215 сказал, Вы должны использовать
WebDriverWaitчтобы дождаться элемента, расположенного на Вашей странице:from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.common.exceptions import TimeoutException browser = webdriver.Firefox() browser.get("url") delay = 3 # seconds try: 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!"я использовал его для проверки оповещения. Вы можете использовать любые другие методы типа найти локатор.
EDIT 1:
Я должен упомянуть, что
webdriverбудет ждать загрузки страницы по умолчанию. Оно не ждет загрузки внутри фреймов или запросов ajax. Это означает, когда вы используете.get('url')Ваш браузер будет ждать, пока страница полностью загружена, а затем перейти к следующей команде в код. Но когда вы отправляете запрос ajax,webdriverне ждет, и это ваша ответственность, чтобы ждать соответствующее количество времени для страницы или части страницы для загрузки; так что есть модуль с именемexpected_conditions.
пыталась передать
find_element_by_idконструктораpresence_of_element_located(как показано на принято отвечать) причинилNoSuchElementExceptionдолжен быть поднят. Мне пришлось использовать синтаксис fragles'комментарий:from selenium import webdriver from selenium.common.exceptions import TimeoutException from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By driver = webdriver.Firefox() driver.get('url') timeout = 5 try: 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"Это соответствует пример в документации. Вот ссылка на документация для By.
найти ниже 3 способами:
readyState
проверка состояния готовности страницы (ненадежно):
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вспомогательная функция хороша, но к сожалениюclick_through_to_new_pageоткрыт для условия гонки, где нам удается выполнить скрипт на старой странице, прежде чем браузер начнет обработку щелчка, иpage_has_loadedпросто возвращает true сразу.
idсравнение новых идентификаторов страниц с старый:
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возможно, что сравнение идентификаторов не так эффективно, как ожидание устаревших ссылочных исключений.
staleness_ofиспользуя
staleness_ofспособ:@contextlib.contextmanager def 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))
для получения более подробной информации, проверьте Гарри.
от selenium/webdriver/support/wait.py
driver = ... from selenium.webdriver.support.wait import WebDriverWait element = WebDriverWait(driver, 10).until( lambda x: x.find_element_by_id("someId"))
как говорится в ответ от Дэвида Каллена, я видел, всегда рекомендуется использовать строку следующего вида:
element_present = EC.presence_of_element_located((By.ID, 'element_id')) WebDriverWait(driver, timeout).until(element_present)мне было трудно найти где-нибудь все возможные локаторы, которые можно использовать с
Byсинтаксис, поэтому я подумал, что было бы полезно предоставить здесь список. Согласно веб-скребок с Python Райан Митчелл:
IDиспользуется в Примере; находит элементы по их атрибуту HTML id
CLASS_NAMEиспользуется для поиска элементов по их атрибуту класса HTML. Почему это функция
CLASS_NAMEне простоCLASS? Используя формуobject.CLASSсоздаст проблемы для Java-библиотеки Selenium, где.class- это зарезервированный метод. Для того, чтобы сохранить синтаксис Селена последовательный между разными языками,CLASS_NAMEбыл использован вместо.
CSS_SELECTORнайти элементы по их классу, идентификатору или имени тега, используя
#idName,.className,tagNameконвенции.
LINK_TEXTнаходит HTML теги по тексту, который они содержат. Например, ссылка говорит, что "далее" можно выбрать с помощью
(By.LINK_TEXT, "Next").
PARTIAL_LINK_TEXTаналогично
LINK_TEXT, но соответствует частичной строке.
NAMEнаходит HTML-теги по атрибуту name. Это удобно для HTML-форм.
TAG_NAMEплавники HTML теги по их имени тега.
XPATHиспользует выражение XPath ... чтобы выбрать соответствующие элементы.
на боковой ноте, вместо прокрутки вниз 100 раз, вы можете проверить, нет ли больше изменений в DOM (мы находимся в случае нижней части страницы, загруженной AJAX lazy-loaded)
def scrollDown(driver, value): driver.execute_script("window.scrollBy(0,"+str(value)+")") # Scroll down the page def scrollDownAllTheWay(driver): old_page = driver.page_source while True: logging.debug("Scrolling loop") for i in range(2): scrollDown(driver, 500) time.sleep(2) new_page = driver.page_source if new_page != old_page: old_page = new_page else: break return True
Как насчет того, чтобы поместить WebDriverWait в цикл While и поймать исключения.
from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException browser = webdriver.Firefox() browser.get("url") delay = 3 # seconds while True: try: WebDriverWait(browser, delay).until(EC.presence_of_element_located(browser.find_element_by_id('IdOfMyElement'))) print "Page is ready!" break # it will break from the loop once the specific element will be present. except TimeoutException: print "Loading took too much time!-Try again"
ты пробовал
driver.implicitly_wait. Это похоже на настройку для драйвера, поэтому вы вызываете его только один раз в сеансе, и он в основном говорит драйверу ждать заданное количество времени, пока каждая команда не будет выполнена.driver = webdriver.Chrome() driver.implicitlyWait(10)Так что если вы установите время ожидания 10 секунд, она выполнит команду как можно скорее, ждать 10 секунд, прежде чем он сдается. Я использовал это в подобных сценариях прокрутки вниз, поэтому я не вижу, почему это не сработает в вашем случае. Надеюсь, что это полезно :)
Comments