Я пытался просмотреть отзывы на веб-сайтах. Для 1 сайта работает нормально. однако, когда я создаю цикл для обхода многих веб-сайтов, он вызывает ошибку
TimeoutException(сообщение, экран, трассировка стека) 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))
Вот некоторые ссылки, которые я пытался просканировать:
Ошибка линии - это второе ожидание, как вы упомянули. Как я могу исправить эту ошибку? Некоторые ссылки имеют более 5 отзывов, поэтому нужно нажать кнопку, некоторые нет. Что мне нужно изменить в коде, который работает в обеих ситуациях?
Отловите ошибку тайм-аута с помощью команды «Попробовать и исключить» -w3schools.com/python/python_try_except.asp — вам также потребуется импортировать эту ошибку в начале вашего скрипта.
Как упоминалось в комментариях, время ожидания истекло, потому что вы ищете несуществующую кнопку.
Вам нужно поймать ошибку (ошибки) и пропустить эти ошибочные строки. Вы можете сделать это с попробовать и кроме.
Я собрал для вас пример. Он жестко закодирован для одного 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/браузер/4b1a0033-8294-428d-802a-d0d2127c4b6f
я нажал загрузить еще
я нажал загрузить еще
Больше нечего загружать, но я не ошибся
Больше нечего загружать, но я не ошибся
Больше нечего загружать, но я не ошибся
Больше нечего загружать, но я не ошибся (и так далее).
Вот как выглядит мой браузер — обратите внимание на размер полосы прокрутки для ссылки, которую я использовал — похоже, в ней есть все отзывы:
Я бы предложил использовать Infinite While loop
и использовать блок try..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...
Какие ошибки в строке? - тайм-аут происходит, когда
webdriverwait
терпит неудачу, и это вместоnosuchelement
- Подтвердите, что объект существует на ссылке, которая терпит неудачу. Например, ваше второе ожидание — это «a.review-load-more__button.js-review-load-more-button» — значит, это «кнопка «загрузить еще», но что, если для этого нет кнопки? Что делать, если отзывов нет или их больше не нужно загружать? (это истечет время поиска)