Задать вопрос
@SiO4
Начинающий разработчик

Как обойти ограничения при парсинге onoz?

Задача довольно обыденная, нужно собирать цены ~1000 наименований товаров из поисковой выдачи маркетплейса Onoz раз в день...
В кратце опишу работу скрипта: из файла products.txt берется наименование товара для поискового запроса, собираются ссылки из поисковой выдачи, каждая открывается и оттуда берутся нужные данные и так далее по циклу.
Площадка использует защиту cloudflare, антибот и антидудос получилось обойти с помощью selenium undetected_chromedriver. Но при парсинге где-то 10 - 15 позиций парсинг останавливается, браузер фризится и от сервера не приходят ответы. Через некоторое время приходит timeout exception.
При этом, если в этой зависшей копии chromedriver попробовать открыть какую-либо ссылку onoz, ничего не выходит - данные тупо не передаются с сервера, а например google открывается. Соответственно проблемы с интернетом сразу отбрасываются, трабл именно в ограничении сервера, видимо какими-то алгоритмами вычисляется работа скрипта.
Если тут же перезапустить скрипт, то он как ни в чем не бывало продолжает собирать эти несчастные 10-15 позиции и снова фризится. Подскажите, может кто сталкивался с такой проблемой как это можно решить? Может с помощью сторожевой функции, которая будет перезапускать скрипт в случае простоя?

import os
import time
import random
import undetected_chromedriver
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import TimeoutException
from settings import LIMIT 


total_start_time = time.time()
driver = undetected_chromedriver.Chrome()


def ONOZ_scraping(ONOZROW):

    with open('ONOZ_links.txt', encoding="utf-8") as file:
        links = [line.strip() for line in file.readlines()]
    start_time = time.time()
    values = [[]]

    column_index = ONOZCOLUMN

    for link in links:
        driver.get(link)
        time.sleep(random.uniform(1, 1.5))
        price_element = driver.find_element(By.CLASS_NAME, ONOZPRICE).find_element(By.TAG_NAME, 'span').text.replace(' ', '').strip('₽').replace(' ', '')
        print(f"Цена {link} — {price_element} рублей.")
        values[0].extend([link, price_element])

    
    end_time = time.time()
    elapsed_time = round(end_time - start_time, 1)

    print(f"{elapsed_time} сек.")



def ONOZ_collect():
        with open('products.txt', encoding="utf-8") as file:
            links = [line.strip() for line in file.readlines()]

        # Получаем номер строки, с которой нужно начать парсинг
        ONOZROW = 1
        if os.path.isfile('ONOZ_row.txt'):
            with open('ONOZ_row.txt', 'r') as f:
                ONOZROW = int(f.read().strip())

        try:
            for i, link in enumerate(links[ONOZROW-1:], start=ONOZROW):
                driver.get(f'https://www.ONOZ.ru/search/?from_global=true&sorting=ONOZ_card_price&text={link}')
                time.sleep(1.5)
                main_element = driver.find_element(By.CLASS_NAME, ONOZCARD)
                elements = main_element.find_elements(By.XPATH, "./div")
                limit = LIMIT
                # Проходим по каждому элементу, извлекаем из него ссылку и обрезаем ее
                ONOZ_links = []
                for o, element in enumerate(elements):
                    if o >= limit:
                        break
                    try:
                        ONOZ_link = element.find_element(By.TAG_NAME, "a").get_attribute("href").split("/")[:5]
                        ONOZ_link = "/".join(ONOZ_link)
                        ONOZ_links.append(ONOZ_link)
                    except NoSuchElementException:
                        print("Элемент не найден")
                    
                with open('ONOZ_links.txt', 'w', encoding="utf-8") as file: 
                    for ONOZ_link in ONOZ_links:
                        if ONOZ_link.strip():
                            file.write(f"{ONOZ_link.strip()}\n")
                print(f"#{i} Сбор ссылок на ONOZ по товару {link} завершен.")
                ONOZ_scraping(i)     
                with open('ONOZ_row.txt', 'w') as f:
                    f.write(str(i))
        except TimeoutException:
             raise          

        driver.quit()
        total_end_time = time.time()
        total_elapsed_time = round((total_end_time - total_start_time) / 60, 1)
        print(f" Парсинг завершен. Длительность парсинга: {total_elapsed_time} мин.")
ONOZ_collect()
  • Вопрос задан
  • 439 просмотров
Подписаться 1 Сложный 1 комментарий
Решения вопроса 1
dimonchik2013
@dimonchik2013
non progredi est regredi
time.sleep(1.5)
меняешь на
time.sleep(random(8,21))
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
zkrvndm
@zkrvndm
Архитектор решений
Очевидно вы упирайтесь в лимит запросов, многие сайты так делают, даже я сам так делаю: если от пользователя поступило слишком много запросов, то текущий запрос тормозится пока не восстановится лимит.

Обходится такая защита обычно при помощи прокси, при помощи множества прокси.
Ответ написан
Комментировать
@withannad2023
Можно попробовать готовое решение по обходу блокировок
curl --proxy brd.superproxy.io:22225 --proxy-user brd-customer--zone-: "https://lumtest.com/myip.json"

Более подробное описание API https://get.brightdata.com/unlocker_api
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы