Подтвердить что ты не робот

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

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

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

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

4b9b3361

Ответ 1

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

Я использовал его для проверки предупреждений. Вы можете использовать любые другие методы, чтобы найти локатор.

РЕДАКТИРОВАТЬ 1:

Я должен отметить, что webdriver будет ожидать загрузки страницы по умолчанию. Он не дожидается загрузки внутри фреймов или запросов ajax. Это означает, что когда вы используете .get('url'), ваш браузер будет ждать, пока страница будет полностью загружена, а затем перейдите к следующей команде в коде. Но когда вы отправляете запрос ajax, webdriver не ждет, и ваша ответственность - ждать соответствующего количества времени для загрузки страницы или части страницы; поэтому существует модуль с именем expected_conditions.

Ответ 2

Попытка передать find_element_by_id конструктору для presence_of_element_located (как показано в принятом ответе), вызвала NoSuchElementException. Мне пришлось использовать синтаксис в fragles comment:

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"

Это соответствует примеру в документации. Ниже приведена ссылка на документацию для.

Ответ 3

Найдите ниже 3 метода:

readyState

Проверка страницы 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'

Вспомогательная функция 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))

Для более подробной информации, проверьте Гарри блог.

Ответ 4

Из селена /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"))

Ответ 5

Как уже упоминалось в ответе Дэвида Каллена, я всегда рекомендовал использовать строку, подобную следующей:

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 создаст проблемы для библиотеки Selenium Java, где .class является зарезервированным методом. Чтобы сохранить синтаксис Selenium в разных языках, вместо этого использовалось CLASS_NAME.

CSS_SELECTOR

Найдите элементы по их классу, идентификатору или имени тега, используя #idName, .className, tagName.

LINK_TEXT

Находит теги HTML по тексту, который они содержат. Например, ссылка "Next" может быть выбрана с помощью (By.LINK_TEXT, "Next").

PARTIAL_LINK_TEXT

Похож на LINK_TEXT, но соответствует частичной строке.

NAME

Находит теги HTML по их атрибуту имени. Это удобно для HTML-форм.

TAG_NAME

Подбирает теги HTML по имени тега.

XPATH

Использует выражение XPath... для выбора подходящих элементов.

Ответ 6

На боковой ноте, вместо прокрутки вниз 100 раз, вы можете проверить, нет ли каких-либо изменений в DOM (мы имеем дело с тем, что нижняя часть страницы была AJAX ленивой).

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

Ответ 7

Как поместить 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"

Ответ 8

Здесь я сделал это, используя довольно простую форму:

from selenium import webdriver
browser = webdriver.Firefox()
browser.get("url")
searchTxt=''
while not searchTxt:
    try:    
      searchTxt=browser.find_element_by_name('NAME OF ELEMENT')
      searchTxt.send_keys("USERNAME")
    except:continue

Ответ 9

Вы пробовали driver.implicitly_wait. Это похоже на настройку для драйвера, поэтому вы вызываете его только один раз в сеансе, и он в основном говорит драйверу подождать определенное количество времени, пока каждая команда не может быть выполнена.

driver = webdriver.Chrome()
driver.implicitly_Wait(10)

Таким образом, если вы установите время ожидания 10 секунд, оно выполнит команду как можно скорее, ожидая 10 секунд, прежде чем она сдастся. Я использовал это в похожих сценариях прокрутки вниз, поэтому я не понимаю, почему это не сработает в вашем случае. Надеюсь, это полезно.