Ошибка при парсинге сайта на python
Разобраться с кодом, чтобы работал корректно 24 на 7, в парсере не сильно силен, но не понимаю как исправить эту ошибку(постоянно вылетает) через рандомное время, может отработать как 2 часа, так и 3 дня без проблем, но рано или поздно вылетает. Запускаю парсер на сервере через tmux, чтобы видеть в консоли как все работает. Запустил код с бесконечным циклом запуска, но ошибка стала чаще выявляться и код все равно отваливается. Прикрепляю код:
import platform
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from bs4 import BeautifulSoup
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
import app.database.request as rq
import asyncio
import os
import time
import logging
import sys
import traceback
import random
from selenium.common.exceptions import WebDriverException, TimeoutException
# Настройка логирования
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('scraper.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
USER_AGENTS = [
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:120.0) Gecko/20100101 Firefox/120.0",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:120.0) Gecko/20100101 Firefox/120.0"
]
def get_random_user_agent():
return random.choice(USER_AGENTS)
def configure_driver_options():
options = Options()
# Обязательные настройки
options.add_argument("--no-sandbox")
options.add_argument("--disable-dev-shm-usage")
options.add_argument("--disable-gpu")
options.add_argument("--window-size=1920,1080")
options.add_argument("--disable-extensions")
# Для Linux всегда используем headless
if platform.system() == "Linux":
options.add_argument("--headless=new")
# Дополнительные настройки для стабильности
options.add_argument("--disable-blink-features=AutomationControlled")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
return options
def create_driver():
try:
options = configure_driver_options()
# Настройка сервиса с автоматическим управлением драйвером
service = Service(
ChromeDriverManager().install(),
service_args=['--verbose'],
log_path='chromedriver.log'
)
driver = webdriver.Chrome(service=service, options=options)
# Настройки таймаутов
driver.set_page_load_timeout(CONFIG['timeouts']['page_load'])
driver.implicitly_wait(10) # Базовый implicit wait
# Установка случайного User-Agent
driver.execute_cdp_cmd('Network.setUserAgentOverride', {
"userAgent": get_random_user_agent()
})
return driver
except Exception as e:
logger.error(f"Ошибка создания драйвера: {str(e)}")
logger.error(traceback.format_exc())
raise
async def human_type(element, text):
for char in text:
element.send_keys(char)
await asyncio.sleep(random.uniform(0.1, 0.3))
async def login(driver):
for attempt in range(CONFIG['max_errors']['login']):
try:
logger.info(f"Попытка входа {attempt + 1}/{CONFIG['max_errors']['login']}")
# Обновляем User-Agent
driver.execute_cdp_cmd('Network.setUserAgentOverride', {
"userAgent": get_random_user_agent()
})
# Загрузка страницы входа
driver.get(CONFIG['login_url'])
# Ожидание элементов формы
WebDriverWait(driver, CONFIG['timeouts']['element_wait']).until(
EC.presence_of_element_located((By.NAME, 'login')))
# Заполнение формы
username = driver.find_element(By.NAME, 'login')
username.clear()
await human_type(username, CONFIG['credentials']['username'])
password = driver.find_element(By.NAME, 'pass')
password.clear()
await human_type(password, CONFIG['credentials']['password'])
# Клик по кнопке входа
login_button = WebDriverWait(driver, CONFIG['timeouts']['element_wait']).until(
EC.element_to_be_clickable((By.XPATH, '//input[@type="submit" and @value="Войти"]')))
await asyncio.sleep(random.uniform(0.5, 1.5))
login_button.click()
# Проверка успешного входа
await asyncio.sleep(3)
if "orders" in driver.current_url or "login" not in driver.current_url:
logger.info("Авторизация успешна")
return True
logger.warning(f"Попытка входа {attempt + 1} не удалась")
except Exception as e:
logger.error(f"Ошибка при входе (попытка {attempt + 1}): {str(e)}")
if attempt == CONFIG['max_errors']['login'] - 1:
raise
await asyncio.sleep(5 * (attempt + 1))
return False
async def process_table(driver):
try:
# Ожидаем загрузку таблицы и кнопки
WebDriverWait(driver, CONFIG['timeouts']['element_wait']).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "table.rows")))
html = driver.page_source
soup = BeautifulSoup(html, 'html.parser')
table = soup.select_one('table.rows')
if not table:
logger.warning("Таблица не найдена")
return False
# Получаем все строки с данными
rows = table.select('tbody tr')
if not rows:
logger.warning("Нет строк данных в таблице")
return False
# Обрабатываем только первую строку (самую новую заявку)
first_row = rows[0]
notify_button = first_row.select_one('a.notify_seen')
if not notify_button:
logger.info("Кнопка 'отметить как просмотренную' отсутствует - пропускаем")
return False
# Извлекаем данные из строки
data = [td.get_text(strip=True) for td in first_row.select('td')]
logger.info(f"Получены данные: {data}")
try:
# Находим и кликаем кнопку через Selenium
button = WebDriverWait(driver, CONFIG['timeouts']['element_wait']).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, 'a.notify_seen')))
driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", button)
await asyncio.sleep(random.uniform(0.5, 1.5)) # Естественная задержка
button.click()
logger.info("Заявка отмечена как просмотренная")
# Проверяем успешность клика (можно добавить ожидание изменения состояния)
await asyncio.sleep(2)
# Сохраняем данные в БД
await rq.insert_data(data)
return True
except Exception as e:
logger.error(f"Ошибка при обработке кнопки: {str(e)}")
return False
except Exception as e:
logger.error(f"Ошибка обработки таблицы: {str(e)}")
return False
async def scrape_data(driver):
error_count = 0
while error_count < CONFIG['max_errors']['scraping']:
try:
logger.info("Загрузка страницы с заявками...")
# Обновляем User-Agent
driver.execute_cdp_cmd('Network.setUserAgentOverride', {
"userAgent": get_random_user_agent()
})
# Загрузка страницы с таймаутом
try:
driver.get(CONFIG['data_url'])
WebDriverWait(driver, CONFIG['timeouts']['element_wait']).until(
EC.presence_of_element_located((By.CSS_SELECTOR, "table.rows")))
logger.info("Таблица успешно загружена")
error_count = 0 # Сброс счетчика ошибок при успехе
# Обработка данных таблицы
if await process_table(driver):
# Случайная задержка между запросами
delay = random.randint(*CONFIG['timeouts']['between_requests'])
logger.info(f"Ожидание {delay} секунд перед следующим запросом...")
await asyncio.sleep(delay)
continue
except TimeoutException:
logger.warning("Таймаут при загрузке таблицы")
error_count += 1
save_page_source(driver, "timeout_error")
except WebDriverException as e:
logger.error(f"Ошибка WebDriver: {str(e)}")
error_count += 1
save_page_source(driver, "webdriver_error")
# Задержка перед повторной попыткой
logger.info(f"Повторная попытка через {CONFIG['timeouts']['retry_delay']} секунд...")
await asyncio.sleep(CONFIG['timeouts']['retry_delay'])
except Exception as e:
logger.error(f"Критическая ошибка: {str(e)}")
error_count += 1
if error_count >= CONFIG['max_errors']['scraping']:
raise Exception("Превышено максимальное количество ошибок")
await asyncio.sleep(CONFIG['timeouts']['retry_delay'] * 2)
def save_page_source(driver, prefix=""):
try:
timestamp = int(time.time())
filename = f"debug/page_source_{prefix}_{timestamp}.html"
os.makedirs(os.path.dirname(filename), exist_ok=True)
with open(filename, "w", encoding="utf-8") as file:
file.write(driver.page_source)
logger.info(f"Сохранен HTML: {filename}")
except Exception as e:
logger.error(f"Ошибка при сохранении HTML: {str(e)}")
async def scraping_session():
driver = None
try:
driver = create_driver()
# Проверка работоспособности драйвера
driver.get("about:blank")
if "about:blank" not in driver.current_url:
raise Exception("Драйвер не смог загрузить тестовую страницу")
# Авторизация
if not await login(driver):
logger.error("Не удалось авторизоваться")
return False
# Сбор данных
await scrape_data(driver)
return True
except Exception as e:
logger.error(f"Ошибка в сессии сбора данных: {str(e)}")
logger.error(traceback.format_exc())
save_page_source(driver, "session_error")
return False
finally:
if driver:
try:
driver.quit()
except Exception as e:
logger.error(f"Ошибка при закрытии драйвера: {str(e)}")
async def main():
restarts = 0
while restarts < CONFIG['max_errors']['restarts']:
try:
logger.info(f"=== Запуск программы (попытка {restarts + 1}/{CONFIG['max_errors']['restarts']}) ===")
if await scraping_session():
logger.info("Сессия успешно завершена")
break
restarts += 1
if restarts < CONFIG['max_errors']['restarts']:
logger.info(f"Перезапуск через {CONFIG['timeouts']['retry_delay']} секунд...")
await asyncio.sleep(CONFIG['timeouts']['retry_delay'])
except KeyboardInterrupt:
logger.info("Программа завершена по запросу пользователя")
break
except Exception as e:
logger.error(f"Критическая ошибка: {str(e)}")
restarts += 1
if restarts < CONFIG['max_errors']['restarts']:
logger.info(f"Перезапуск через {CONFIG['timeouts']['retry_delay'] * 2} секунд...")
await asyncio.sleep(CONFIG['timeouts']['retry_delay'] * 2)
else:
logger.error("Достигнуто максимальное количество перезапусков")
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
logger.info("Программа завершена")
sys.exit(0)
except Exception as e:
logger.error(f"Фатальная ошибка: {str(e)}")
sys.exit(1)введите сюда код
Через несколько собранных заявок вылетает ошибка:
Ошибка при обработке заявки *****(попытка 1/3): Message:
Stacktrace:
#0 0x55fa74f88ffa <unknown>
#1 0x55fa74a47970 <unknown>
#2 0x55fa74a99385 <unknown>
#3 0x55fa74a995b1 <unknown>
#4 0x55fa74ae83c4 <unknown>
#5 0x55fa74abf2bd <unknown>
#6 0x55fa74ae570c <unknown>
#7 0x55fa74abf063 <unknown>
#8 0x55fa74a8b328 <unknown>
#9 0x55fa74a8c491 <unknown>
#10 0x55fa74f5042b <unknown>
#11 0x55fa74f542ec <unknown>
#12 0x55fa74f37a22 <unknown>
#13 0x55fa74f54e64 <unknown>
#14 0x55fa74f1bbef <unknown>
#15 0x55fa74f77558 <unknown>
#16 0x55fa74f77736 <unknown>
#17 0x55fa74f87e76 <unknown>
#18 0x7fee75c62609 start_thread
- ERROR - Ошибка при входе (попытка 1): Message: timeout: Timed out receiving message from renderer: 56.926
(Session info: chrome=134.0.6998.165)
Stacktrace:
#0 0x562c9b285ffa <unknown>
#1 0x562c9ad44970 <unknown>
#2 0x562c9ad2bd0d <unknown>
#3 0x562c9ad2b9ef <unknown>
#4 0x562c9ad29739 <unknown>
#5 0x562c9ad2a17f <unknown>
#6 0x562c9ad398bb <unknown>
#7 0x562c9ad52dbe <unknown>
#8 0x562c9ad594cb <unknown>
#9 0x562c9ad2a890 <unknown>
#10 0x562c9ad52b17 <unknown>
#11 0x562c9ade2a4a <unknown>
#12 0x562c9adbc063 <unknown>
#13 0x562c9ad88328 <unknown>
#14 0x562c9ad89491 <unknown>
#15 0x562c9b24d42b <unknown>
#16 0x562c9b2512ec <unknown>
#17 0x562c9b234a22 <unknown>
#18 0x562c9b251e64 <unknown>
#19 0x562c9b218bef <unknown>
#20 0x562c9b274558 <unknown>
#21 0x562c9b274736 <unknown>
#22 0x562c9b284e76 <unknown>
#23 0x7f57d8bfe609 start_thread
Как можно решить эту проблему?