2014-10-25 7 views
61

Я хочу очистить все данные страницы, реализованные бесконечным прокруткой. Выполняется следующий код python.Как подождать, пока страница будет загружена Selenium для Python?

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

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

+0

Это может помочь узнать немного больше о странице. Являются ли элементы последовательными или предсказуемыми? Вы можете дождаться загрузки элементов, проверив visiblity с помощью id или xpath. – user2272115

+0

. Я просматриваю следующую страницу: http://www.pinterest.com/cremedelacrumb/yum/ – apogne

+0

Возможный дубликат [Надежное обнаружение загрузки страницы или тайм-аута, Selenium 2] (http://stackoverflow.com/questions/18729483/reliably-detect-page-load-or-time-out-selenium-2) – kenorb

ответ

82

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.

+0

Что такое "IdOfMyElement"? Это то, что я должен предсказать, как индекс чего-то будет загружен заново? Например, я хочу просканировать следующую страницу: http://www.pinterest.com/cremedelacrumb/yum/ – apogne

+0

Вы должны найти элемент на своей странице, который, как вы уверены, всегда существует на странице. «IdOfMyElement» означает идентификатор элемента на странице; если он не имеет идентификатора, вы можете использовать любой другой тип локатора, например 'xpath'. –

+0

Я думаю, что это не должно быть что-то всегда существующее. Это должно быть то, что будет загружено после прокрутки вниз. Я прав? Например, можете ли вы рассказать мне, что представляет собой этот элемент страницы, о которой я говорил раньше? – apogne

18

Найти ниже 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' 

Сравнивая новые идентификаторы страниц со старым:

def page_has_loaded2(): 
    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 метода:

@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)) 

Для получения дополнительной информации, проверьте Harry's blog.

36

Пытается пройти find_element_by_id к конструктору для presence_of_element_located (как показано на рисунке accepted answer), вызвав поднятие 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" 

Это соответствует example in the documentation. Вот ссылка на documentation for By.

+1

Спасибо! да, это было необходимо и мне. ID не является единственным атрибутом, который можно использовать, чтобы получить полный список, используйте help (By). Например. Я использовал 'EC.presence_of_element_located ((By.XPATH," // * [@ title = 'Check All Q1'] "))' –

+0

Так оно и работает для меня! Я написал дополнительный [ответ] (http://stackoverflow.com/a/40037216/5802289), расширяющийся на разных локаторах, доступных с объектом 'By'. – J0ANMM

8

Как уже упоминалось в answer from David Cullen, я видел, всегда рекомендуется использовать строку как следующий:

element_present = EC.presence_of_element_located((By.ID, 'element_id')) 
    WebDriverWait(driver, timeout).until(element_present) 

Это было трудно для меня, чтобы найти где-нибудь все возможные локаторы, которые могут быть использованы с синтаксисом By , поэтому я подумал, что было бы полезно представить здесь список. Согласно Web Scraping with Python Райан Митчелл:

ID

Используется в примере; находит элементы по их HTML идентификатор атрибута

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-теги их имени атрибута. Это удобно для форм HTML.

TAG_NAME

Ласты HTML-теги по их имени тега.

XPATH

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

+3

В [документации для] (http://selenium-python.readthedocs.io/api.html?highlight=#module-selenium.webdriver.common.by) перечислены атрибуты, которые могут использоваться в качестве локаторов. –

+0

Это то, что я искал! Благодаря! Ну, теперь это должно быть проще найти, поскольку Google отправил меня на этот вопрос, но не в официальную документацию. – J0ANMM

1

Как о вводе 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" 
1

На стороне записки, вместо прокрутки вниз 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 
+0

Это полезно. Однако что представляют собой 500? Достаточно ли этого, чтобы добраться до конца страницы? – Moondra

+0

Это количество, которое должна прокручивать страница ... вы должны установить его как можно выше. Я только узнал, что этого числа было достаточно для меня, поскольку он прокручивает страницу до нижней части, пока элементы AJAX не будут ленивы загружены, что еще раз вызовет повторную загрузку страницы – raffamaiden