Подождите, пока страница загрузится с Selenium WebDriver для Python
Я хочу очистить все данные страницы, реализованные бесконечной прокруткой. Работает следующий код на python.
for i in range(100):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(5)
Это означает, что каждый раз, когда я прокручиваю страницу вниз, мне нужно подождать 5 секунд, чего обычно достаточно, чтобы страница завершила загрузку вновь созданного содержимого. Но это может быть нецелесообразно по времени. Страница может завершить загрузку нового содержимого в течение 5 секунд. Как я могу определить, завершала ли страница загрузку нового содержимого каждый раз, когда я прокручиваю страницу вниз? Если я смогу это обнаружить, я смогу снова прокрутить вниз, чтобы увидеть больше содержимого, как только я узнаю, что страница завершила загрузку. Это экономит больше времени.
Переведено автоматически
Ответ 1
webdriver
Будет ждать загрузки страницы по умолчанию с помощью .get()
метода.
Поскольку вы, возможно, ищете какой-то конкретный элемент, как сказал @User, вам следует использовать 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
запрос. Мне пришлось использовать синтаксис в фрагментах' 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"
Это соответствует примеру в документации. Вот ссылка на документацию для By.
Ответ 3
Найдите ниже 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'
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
Как упоминалось в ответе Дэвида Каллена, я всегда видел рекомендации использовать строку, подобную следующей:
element_present = EC.presence_of_element_located((By.ID, 'element_id'))
WebDriverWait(driver, timeout).until(element_present)
Мне было сложно найти где-нибудь все возможные локаторы, которые можно использовать с By
, поэтому я подумал, что было бы полезно предоставить список здесь.
Согласно Web Scraping with Python Райана Митчелла:
ID
Используется в примере; находит элементы по их атрибуту HTML id
CLASS_NAME
Используется для поиска элементов по их атрибуту класса HTML. Почему эта функция
CLASS_NAME
не простаяCLASS
? Использование формыobject.CLASS
создаст проблемы для библиотеки Java Selenium, где.class
это зарезервированный метод. Чтобы сохранить синтаксис Selenium согласованным между разными языками,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 ... для выбора соответствующих элементов.