Espere hasta que la página se cargue con Selenium WebDriver para Python

Resuelto apogne asked hace 10 años • 16 respuestas

Quiero extraer todos los datos de una página implementada mediante un desplazamiento infinito. El siguiente código Python funciona.

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

Esto significa que cada vez que me desplazo hacia abajo, debo esperar 5 segundos, lo que generalmente es suficiente para que la página termine de cargar el contenido recién generado. Pero es posible que esto no ahorre tiempo. La página puede terminar de cargar los nuevos contenidos en 5 segundos. ¿Cómo puedo detectar si la página terminó de cargar el nuevo contenido cada vez que me desplazo hacia abajo? Si puedo detectar esto, puedo desplazarme hacia abajo nuevamente para ver más contenidos una vez que sepa que la página terminó de cargarse. Esto es más eficiente en cuanto a tiempo.

apogne avatar Oct 26 '14 03:10 apogne
Aceptado

Esperará webdrivera que se cargue una página de forma predeterminada mediante .get()el método.

Como puedes estar buscando algún elemento específico como dijo @user227215, debes usar WebDriverWaitpara esperar por un elemento ubicado en tu página:

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

Lo he usado para verificar alertas. Puede utilizar cualquier otro tipo de método para encontrar el localizador.

EDITAR 1:

Debo mencionar que webdriveresperará a que se cargue una página de forma predeterminada. No espera la carga dentro de los marcos ni las solicitudes de ajax. Significa que cuando use .get('url'), su navegador esperará hasta que la página esté completamente cargada y luego pasará al siguiente comando en el código. Pero cuando publica una solicitud ajax, webdriverno espera y es su responsabilidad esperar una cantidad de tiempo adecuada para que se cargue la página o parte de la página; entonces hay un módulo llamado expected_conditions.

Zeinab Abbasimazar avatar Oct 25 '2014 21:10 Zeinab Abbasimazar

Intentar pasar find_element_by_idal constructor for presence_of_element_located(como se muestra en la respuesta aceptada ) provocó NoSuchElementExceptionun aumento. Tuve que usar la sintaxis en el comentario de 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"

Esto coincide con el ejemplo de la documentación . Aquí hay un enlace a la documentación de By .

 avatar May 18 '2016 14:05

Encuentre a continuación 3 métodos:

estado listo

Comprobando el estado de preparación de la página (no confiable):

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'

La wait_forfunción auxiliar es buena, pero desafortunadamente click_through_to_new_pageestá abierta a la condición de carrera en la que logramos ejecutar el script en la página anterior, antes de que el navegador haya comenzado a procesar el clic, y page_has_loadedsimplemente devuelve verdadero de inmediato.

id

Comparando los nuevos ID de página con los antiguos:

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

Es posible que comparar identificadores no sea tan efectivo como esperar excepciones de referencia obsoletas.

staleness_of

Método de uso 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))

Para obtener más detalles, consulte el blog de Harry .

kenorb avatar May 21 '2015 23:05 kenorb

Como se menciona en la respuesta de David Cullen , siempre he visto recomendaciones para usar una línea como la siguiente:

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

Fue difícil para mí encontrar en algún lugar todos los posibles localizadores que se pueden usar con By, así que pensé que sería útil proporcionar la lista aquí. Según Web Scraping con Python de Ryan Mitchell:

ID

Usado en el ejemplo; encuentra elementos por su atributo de identificación HTML

CLASS_NAME

Se utiliza para buscar elementos por su atributo de clase HTML. ¿Por qué esta función CLASS_NAMEno es simple CLASS? Usar el formulario object.CLASS crearía problemas para la biblioteca Java de Selenium, donde .classhay un método reservado. CLASS_NAMEEn su lugar, se utilizó para mantener la sintaxis de Selenium coherente entre diferentes idiomas .

CSS_SELECTOR

Busca elementos por su clase , ID o nombre de etiqueta, utilizando la convención #idName, ..classNametagName

LINK_TEXT

Encuentra etiquetas HTML por el texto que contienen. Por ejemplo, se puede seleccionar un enlace que dice "Siguiente" usando (By.LINK_TEXT, "Next").

PARTIAL_LINK_TEXT

Similar a LINK_TEXT, pero coincide con una cadena parcial.

NAME

Encuentra etiquetas HTML por su atributo de nombre. Esto es útil para formularios HTML.

TAG_NAME

Encuentra etiquetas HTML por su nombre de etiqueta.

XPATH

Utiliza una expresión XPath... para seleccionar elementos coincidentes.

J0ANMM avatar Oct 14 '2016 07:10 J0ANMM

Desde selenio/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"))
Carl avatar Jan 26 '2017 12:01 Carl