【问题标题】:Crawl data by Selenium but throws errors TimeoutExceptionSelenium 抓取数据但抛出错误 TimeoutException
【发布时间】:2020-12-11 10:02:15
【问题描述】:

我试图抓取网站中的评论。对于 1 个网站,它运行良好。但是,当我创建一个循环以在许多网站中进行爬网时,它会引发错误引发

TimeoutException(message, screen, stacktrace) TimeoutException

我现在尝试将等待时间从 30 增加到 50,但仍然无法正常运行。 这是我的代码:

import requests
import pandas as pd
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 bs4 import BeautifulSoup
from datetime import datetime

start_time = datetime.now()

result = pd.DataFrame()
df = pd.read_excel(r'D:\check_bols.xlsx')
ids = df['ids'].values.tolist() 

link = "https://www.bol.com/nl/ajax/dataLayerEndpoint.html?product_id="

for i in ids:
    
    link3 = link + str(i[-17:].replace("/",""))
    op = webdriver.ChromeOptions()
    op.add_argument('--ignore-certificate-errors')
    op.add_argument('--incognito')
    op.add_argument('--headless')
    driver = webdriver.Chrome(executable_path='D:/chromedriver.exe',options=op)
    driver.get(i)
    WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[data-test='consent-modal-confirm-btn']>span"))).click()
    WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a.review-load-more__button.js-review-load-more-button"))).click()

    soup = BeautifulSoup(driver.page_source, 'lxml')

    product_attributes = requests.get(link3).json()

    reviewtitle = [i.get_text() for i in soup.find_all("strong", class_="review__title") ]

    url = [i]*len(reviewtitle)

    productid = [product_attributes["dmp"]["productId"]]*len(reviewtitle)
  
    content= [i.get_text().strip()  for i in soup.find_all("div",attrs={"class":"review__body"})]
    
    author = [i.get_text() for i in soup.find_all("li",attrs={"data-test":"review-author-name"})]

    date  = [i.get_text() for i in soup.find_all("li",attrs={"data-test":"review-author-date"})]

    output = pd.DataFrame(list(zip(url, productid,reviewtitle, author, content, date )))
    
    result.append(output)
    
    result.to_excel(r'D:\bols.xlsx', index=False)
    
end_time = datetime.now()
print('Duration: {}'.format(end_time - start_time))

以下是我尝试抓取的一些链接:

link1 link2

【问题讨论】:

  • 哪一行错误? - 当webdriverwait 失败并且它不是nosuchelement 时发生超时 - 验证该对象是否存在于失败的链接上。例如,您的第二个等待是“a.review-load-more__button.js-review-load-more-button” - 这就是“加载更多按钮”,但如果没有按钮怎么办?如果没有评论或没有更多评论要加载怎么办? (它会超时找到它)
  • 行错误是您提到的第二次等待。我该如何解决这个错误?有些链接有超过 5 条评论,所以需要点击按钮,有些则不需要。我应该如何调整适用于这两种情况的代码?
  • 使用 Try 和 except -w3schools.com/python/python_try_except.asp 捕获超时错误 - 您还需要在脚本开始时导入该错误。

标签: python selenium selenium-webdriver selenium-chromedriver timeoutexception


【解决方案1】:

正如 cmets 中所述 - 您超时是因为您正在寻找一个不存在的按钮。

您需要捕获错误并跳过那些失败的行。您可以使用a try and except 来执行此操作。

我为你整理了一个例子。它被硬编码到一个 url(因为我没有你的数据表),它是一个固定循环,目的是保持尝试点击“显示更多”按钮,即使它消失了。

使用此解决方案时,请注意同步时间。每次调用 WebDriverWait 时,如果它不存在,它将等待整个持续时间。完成后您需要退出扩展循环(第一次出错时)并保持同步时间紧凑 - 否则脚本会很慢

首先,将这些添加到您的导入中:

from selenium.common.exceptions import TimeoutException
from selenium.common.exceptions import StaleElementReferenceException

然后这将运行而不是错误:

#not a fixed url:
driver.get('https://www.bol.com/nl/p/Matras-180x200-7-zones-koudschuim-premium-plus-tijk-15-cm-hard/9200000130825457/')

#accept the cookie once
WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[data-test='consent-modal-confirm-btn']>span"))).click()
   
for i in range(10):
    try:
        WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a.review-load-more__button.js-review-load-more-button"))).click()
        print("I pressed load more")
    except (TimeoutException, StaleElementReferenceException):
        pass
        print("No more to load - but i didn't fail")

控制台的输出是这样的:

DevTools 监听 ws://127.0.0.1:51223/devtools/browser/4b1a0033-8294-428d-802a-d0d2127c4b6f

我按下加载更多

我按下加载更多

没有更多的加载 - 但我没有失败

没有更多的加载 - 但我没有失败

没有更多的加载 - 但我没有失败

没有更多的加载 - 但我没有失败 (等等)。

这是我的浏览器的外观 - 请注意我使用的链接的滚动条的大小 - 看起来它得到了所有评论:

【讨论】:

    【解决方案2】:

    我建议使用Infinite While loop 并使用try..except 块。如果找到元素,它将单击元素 else 语句将转到 except 块并退出 while 循环。

    driver.get("https://www.bol.com/nl/p/Matras-180x200-7-zones-koudschuim-premium-plus-tijk-15-cm-hard/9200000130825457/")
    WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[data-test='consent-modal-confirm-btn']>span"))).click()
    while True:
        try:
            WebDriverWait(driver, 50).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "a.review-load-more__button.js-review-load-more-button"))).click()
            print("Lode more button found and clicked ")
        except:
            print("No more load more button available on the page.Please exit...")
            break
    

    您的控制台输出将如下所示。

    Lode more button found and clicked 
    Lode more button found and clicked 
    Lode more button found and clicked 
    Lode more button found and clicked 
    No more load more button available on the page.Please exit...
    

    【讨论】:

      猜你喜欢
      • 2020-10-06
      • 2022-01-16
      • 2012-10-21
      • 1970-01-01
      • 1970-01-01
      • 2021-10-18
      • 2018-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多