StaleElementException cuando se itera con Python

Estoy tratando de crear un raspador web básico para los resultados de Amazon. A medida que estoy repitiendo los resultados, a veces llego a la página 5 (a veces solo a la página 2) de los resultados y luego se StaleElementException una StaleElementException . Cuando miro el navegador después de que se lanza la excepción, puedo ver que el controlador / página no se desplazó hacia abajo hasta donde están los números de página (barra inferior).

Mi código:

 driver.get('https://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=sonicare+toothbrush') for page in range(1,last_page_number +1): driver.implicitly_wait(10) bottom_bar = driver.find_element_by_class_name('pagnCur') driver.execute_script("arguments[0].scrollIntoView(true);", bottom_bar) current_page_number = int(driver.find_element_by_class_name('pagnCur').text) if page == current_page_number: next_page = driver.find_element_by_xpath('//div[@id="pagn"]/span[@class="pagnLink"]/a[text()="{0}"]'.format(current_page_number+1)) next_page.click() print('page #',page,': going to next page') else: print('page #: ', page,'error') 

He analizado esta pregunta y supongo que se puede aplicar una solución similar, pero no estoy seguro de cómo encontrar algo en la página que desaparece. Además, según la rapidez con la que se producen las declaraciones de impresión, puedo ver que implicitly_wait(10) esperar implicitly_wait(10) no está esperando realmente 10 segundos completos.

La excepción es apuntar a la línea que comienza con “driver.execute_script”. Esta es la excepción:

 StaleElementReferenceException: Message: The element reference of  is stale; either the element is no longer attached to the DOM, it is not in the current frame context, or the document has been refreshed 

A veces me sale un ValueError:

 ValueError: invalid literal for int() with base 10: '' 

Así que estos errores / excepciones me llevan a creer que algo está sucediendo con la espera de que la página se actualice por completo.

Si solo desea que la secuencia de comandos se repita en todas las páginas de resultados, no necesita ninguna lógica complicada; simplemente haga clic en el botón Siguiente mientras sea posible:

 from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.support.ui import WebDriverWait as wait from selenium.common.exceptions import TimeoutException driver = webdriver.Chrome() driver.get('https://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=sonicare+toothbrush') while True: try: wait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, 'a > span#pagnNextString'))).click() except TimeoutException: break 

PS También tenga en cuenta que implicitly_wait(10) no debe esperar 10 segundos completos , sino que debe esperar hasta 10 segundos para que aparezca el elemento en HTML DOM . Entonces, si el elemento se encuentra dentro de 1 o 2 segundos, entonces se hace esperar y no esperará el descanso 8-9 segundos …

Parece que ya casi estabas allí.

Preservando su concepto de desplazamiento a través de scrollIntoView() e imprimiendo un par de mensajes de depuración útiles, he hecho algunos ajustes menores induciendo a WebDriverWait y puede usar la siguiente solución:

  • Bloque de código:

     from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC options = Options() options.add_argument("start-maximized") options.add_argument('disable-infobars') options.add_argument("--disable-extensions") driver = webdriver.Chrome(chrome_options=options, executable_path=r'C:\Utility\BrowserDrivers\chromedriver.exe') driver.get("https://www.amazon.com/s/ref=nb_sb_noss_1?url=search-alias%3Daps&field-keywords=sonicare+toothbrush") while True: try: current_page_number_element = WebDriverWait(driver, 20).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "span.pagnCur"))) driver.execute_script("arguments[0].scrollIntoView(true);", current_page_number_element) current_page_number = current_page_number_element.get_attribute("innerHTML") WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "span.pagnNextArrow"))).click() print("page # {} : going to next page".format(current_page_number)) except: print("page # {} : error, no more pages".format(current_page_number)) break driver.quit() 
  • Salida de consola:

     page # 1 : going to next page page # 2 : going to next page page # 3 : going to next page page # 4 : going to next page page # 5 : going to next page page # 6 : going to next page page # 7 : going to next page page # 8 : going to next page page # 9 : going to next page page # 10 : going to next page page # 11 : going to next page page # 12 : going to next page page # 13 : going to next page page # 14 : going to next page page # 15 : going to next page page # 16 : going to next page page # 17 : going to next page page # 18 : going to next page page # 19 : going to next page page # 20 : error, no more pages