Подождите, пока страница не будет загружена с Selenium WebDriver для Python



Я хочу очистить все данные страницы, реализованные с помощью бесконечной прокрутки. Следующий код python работает.



for i in range(100):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(5)


Это означает, что каждый раз, когда я прокручиваю вниз, мне нужно подождать 5 секунд, что обычно достаточно для завершения загрузки страницы вновь сгенерированного содержимого. Но, это не может быть эффективным во времени. Страница завершения загрузки нового содержимого в течение 5 секунд. Как я могу определить, закончила ли страница загрузку нового содержимого каждый раз, когда я прокручиваю вниз? Если я могу обнаружить это, я могу прокрутить вниз снова, чтобы увидеть больше содержимого, как только я знаю, что страница закончила загрузку. Это более эффективно.

1665   8  

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

    Ничего не найдено.