Just Eat, один из крупнейших онлайн-рынков доставки еды в Европе, связывающий миллионы клиентов с местными ресторанами. Каждая страница района представляет собой публичный структурированный каталог, показывающий, кто доставляет еду поблизости: название ресторана, кухни, которые он готовит, рейтинг, детали доставки и прямую ссылку на его меню. Эти данные служат чётким сигналом для всех, кто изучает местные рынки питания, отслеживает, какие кухни доминируют в определённом районе, оценивает ценообразование в меню или создаёт инструмент поиска ресторанов.
В этом руководстве показано, как парсить данные Just Eat с помощью Python. Вы создадите небольшой рабочий скрапер, который загружает страницу района Just Eat через Crawling API, парсит чистую запись для каждого ресторана, переходит по ссылке ресторана для получения пунктов меню, обрабатывает пагинацию на основе прокрутки и экспортирует результаты в JSON и CSV. Всё руководство ограничено публичными данными объявлений: именами, кухнями, рейтингами, ссылками и ценами меню, которые любой пользователь видит на странице района или меню без входа в систему.
Что вы создадите
Скрипт на Python, который принимает URL района Just Eat, загружает отрендеренную страницу через Crawling API и извлекает структурированную запись для каждого ресторана. В качестве примера мы используем страницу района London Bridge, ту же, что использовалась в предыдущем руководстве, и извлекаем следующие поля из каждой карточки ресторана:
- Название название ресторана, отображаемое на карточке объявления.
- Кухня теги кухни, например «Pizza, Italian».
- Рейтинг звёздный рейтинг и количество отзывов, например «4.5(26)».
- Ссылка абсолютный URL на собственную страницу меню ресторана.
- Пункты меню для каждого блюда: категория, название, цена и описание со страницы меню ресторана.
Почему обычный запрос не работает на Just Eat
Если направить обычный HTTP-клиент на URL района Just Eat, вы редко получите искомый список ресторанов. Против вас работают два фактора. Во-первых, Just Eat рендерит объявления на стороне клиента: сервер отправляет лёгкую оболочку, а карточки заполняются по мере выполнения JavaScript страницы и прокрутки, поэтому исходный HTML зачастую является пустой сеткой. Во-вторых, сайт быстро выявляет автоматизированный трафик. IP датацентров и паттерны запросов, не похожие на запросы реального браузера, сталкиваются со страницей проверки, CAPTCHA или прямой блокировкой.
Поэтому рабочему скраперу Just Eat нужны сразу две вещи в одном запросе: браузер, рендерящий страницу, и IP, который сайт воспринимает как настоящего посетителя. Можно собрать это самостоятельно с помощью headless-браузера и пула ротируемых резидентных прокси, но поддержание такого стека в рабочем состоянии, это и есть основная работа. Crawling API объединяет оба компонента в одном вызове: вы отправляете URL района, API рендерит страницу за доверенным резидентным IP, обрабатывает ротацию и решение CAPTCHA и возвращает готовый HTML для парсинга.
Предварительные требования
Перед написанием кода необходимо подготовить несколько вещей. Это не займёт много времени.
Базовые знания Python. Вы должны уметь писать и запускать скрипты Python, а также устанавливать пакеты через pip. Если вы новичок в языке, официальная документация Python или любой вводный курс охватывает уровень, необходимый для этого руководства.
Python 3.8 или выше. Проверьте версию командой python --version (или python3 --version). Если Python не установлен, скачайте его с python.org и убедитесь, что Python находится в PATH вашей системы.
Аккаунт Crawlbase и токен. Зарегистрируйтесь для получения бесплатного аккаунта, откройте панель управления и скопируйте токен. Crawlbase выдаёт два токена: обычный для статических сайтов и JavaScript-токен для JS-рендерящихся сайтов, таких как Just Eat. Бесплатный тариф включает до 20 000 бесплатных запросов без карты. Обращайтесь с токеном как с паролем и не добавляйте его в систему контроля версий.
Настройка проекта
Создайте виртуальное окружение, чтобы изолировать зависимости проекта, затем установите две библиотеки, необходимые скраперу. crawlbase является официальным клиентом для Crawling API, а beautifulsoup4 парсит возвращаемый HTML, позволяя извлекать каждое поле из карточек ресторанов по CSS-селектору.
python --version python -m venv just_eat_env source just_eat_env/bin/activate pip install crawlbase beautifulsoup4
В Windows активируйте окружение командой just_eat_env\Scripts\activate вместо строки с source. После установки обеих библиотек создайте файл скрипта, который будет строиться в остальной части руководства:
touch just_eat_scraper.py
Изучение страницы района для поиска селекторов
Для парсинга данных необходимо сначала понять структуру страницы района Just Eat. Откройте страницу района в браузере, например страницу https://www.just-eat.co.uk/area/ec4r3tn для района London Bridge, щёлкните правой кнопкой мыши карточку ресторана и выберите «Inspect». Just Eat маркирует ключевые элементы стабильными атрибутами data-qa, которые значительно надёжнее, чем генерируемые имена утилитарных классов. Это элементы, на которые вы нацеливаетесь:
-
Карточка ресторана:
<div>с атрибутомdata-qa="restaurant-card"оборачивает каждое объявление. -
Название ресторана:
<div>сdata-qa="restaurant-info-name". -
Тип кухни:
<div>сdata-qa="restaurant-cuisine". -
Рейтинг:
<div>сdata-qa="restaurant-ratings". -
Ссылка на ресторан: атрибут
hrefтега<a>внутри карточки, который является относительным, поэтому дополните его значениемhttps://www.just-eat.co.uk.
Шаг 1: Загрузка отрендеренной страницы района
Начните с получения готовой страницы. Импортируйте класс CrawlingAPI, инициализируйте его своим токеном, задайте URL района и выполните запрос. Контент Just Eat загружается асинхронно, поэтому передайте ajax_wait для ожидания динамического контента и page_wait для выдержки нескольких секунд после загрузки. Проверка кода статуса перед парсингом позволяет выявлять ошибки явно, а не молча.
from crawlbase import CrawlingAPI api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) def fetch_listings(url): options = {"ajax_wait": "true", "page_wait": 3000} response = api.get(url, options) if response["status_code"] == 200: return response["body"].decode("utf-8") print(f"Failed to fetch the page. Status: {response['status_code']}") return None if __name__ == "__main__": area_url = "https://www.just-eat.co.uk/area/ec4r3tn" html = fetch_listings(area_url) print(html[:500] if html else "No HTML returned")
Два параметра ожидания важны для сетки, заполняющейся после загрузки. Параметр ajax_wait говорит API ждать завершения загрузки асинхронного контента, а page_wait выдерживает фиксированное количество миллисекунд, чтобы поздно рендерящиеся карточки появились до захвата страницы. Запустите скрипт, и вы должны увидеть настоящую разметку объявлений, а не пустую оболочку или страницу с проверкой. Это подтверждает, что рендеринг работает, прежде чем вы напишете единственный селектор.
Сетка района заполняется только после выполнения JavaScript, а Just Eat блокирует трафик, не похожий на запросы реального браузера. Crawling API принимает токен, запускает страницу в реальном браузере, ротирует через резидентные IP на стороне сервера и обрабатывает решение CAPTCHA, а затем передаёт готовый HTML. Вам не нужно самостоятельно управлять парком headless-браузеров и пулом прокси. Попробуйте на странице района в рамках бесплатного тарифа до 20 000 запросов.
Шаг 2: Парсинг карточек ресторанов с BeautifulSoup
Имея отрендеренный HTML, загрузите его в BeautifulSoup, найдите каждую карточку ресторана и извлеките каждое поле по его селектору data-qa. Каждая карточка содержит название, кухню и рейтинг, а также якорь, относительный href которого вы присоединяете к базовому URL сайта. Небольшой хелпер text_of возвращает пустую строку, когда поле отсутствует, вместо исключения при вызове .text для None.
from bs4 import BeautifulSoup BASE = "https://www.just-eat.co.uk" def text_of(card, selector): el = card.select_one(selector) return el.get_text(strip=True) if el else "" def parse_restaurants(html): soup = BeautifulSoup(html, "html.parser") restaurants = [] cards = soup.select('div[data-qa="restaurant-card"]') for card in cards: try: anchor = card.select_one("a[href]") link = BASE + anchor["href"] if anchor else "" restaurants.append({ "name": text_of(card, 'div[data-qa="restaurant-info-name"]'), "cuisine": text_of(card, 'div[data-qa="restaurant-cuisine"]'), "rating": text_of(card, 'div[data-qa="restaurant-ratings"]'), "link": link, }) except Exception as e: print(f"Skipped a card: {e}") return restaurants
Селектор data-qa="restaurant-card" находит контейнеры объявлений, а select_one считывает каждое поле внутри карточки. Поле рейтинга приходит в виде комбинированной строки вроде "4.5(26)", звёздный балл, за которым следует количество отзывов в скобках; оставьте его в исходном виде и разделите ниже по потоку, если вам нужны два значения отдельно. Ссылка на странице является относительной, поэтому добавление префикса BASE даёт абсолютный URL, по которому можно перейти прямо к меню. Оборачивание каждой карточки в блок try/except означает, что одно некорректное объявление не остановит весь процесс.
Атрибуты data-qa в Just Eat предназначены для собственного тестирования сайта, что делает их более стабильными, чем генерируемые имена классов, но они не являются контрактом. Воспринимайте приведённые выше селекторы как отправную точку. Когда поле возвращается пустым для каждой карточки, заново проверьте живую страницу района в инструментах разработчика браузера и обновите селектор. Периодическое обслуживание селекторов нормально для любого производственного скрапера.
Шаг 3: Обработка пагинации на основе прокрутки
Just Eat не использует пронумерованные страницы. Он использует бесконечную прокрутку: при прокрутке к низу загружается больше ресторанов. Crawling API может управлять этой прокруткой за вас, чтобы вам не нужно было делать это вручную. Замените параметры ожидания на scroll и scroll_interval, что говорит API, сколько секунд продолжать прокрутку и загрузку перед захватом страницы. Рядом с ним не нужен page_wait; интервал прокрутки покрывает ожидание.
def fetch_listings(url): options = {"scroll": "true", "scroll_interval": "20"} response = api.get(url, options) if response["status_code"] == 200: return response["body"].decode("utf-8") print(f"Failed to fetch the page. Status: {response['status_code']}") return None
Здесь scroll_interval установлен равным 20, поэтому API прокручивает в течение 20 секунд перед захватом, достаточно долго для загрузки большинства ресторанов в загруженном районе. Увеличивайте значение для более насыщенных районов и уменьшайте для тихих; более длинная прокрутка занимает больше времени на каждый запрос, поэтому настраивайте её под страницу. С этим на месте parse_restaurants видит полную сетку, а не только первый экран.
Шаг 4: Сборка скрипта объявлений и экспорт в JSON и CSV
Теперь объедините загрузку и парсинг в один рабочий скрипт, а затем запишите записи в JSON и CSV, чтобы вы могли загрузить их в ноутбук или таблицу. Общий список FIELDS синхронизирует порядок столбцов CSV с ключами словаря, чтобы два экспорта никогда не разошлись.
import csv import json from crawlbase import CrawlingAPI from bs4 import BeautifulSoup api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) BASE = "https://www.just-eat.co.uk" FIELDS = ["name", "cuisine", "rating", "link"] def fetch_listings(url): options = {"scroll": "true", "scroll_interval": "20"} response = api.get(url, options) if response["status_code"] == 200: return response["body"].decode("utf-8") print(f"Failed to fetch the page. Status: {response['status_code']}") return None def text_of(card, selector): el = card.select_one(selector) return el.get_text(strip=True) if el else "" def parse_restaurants(html): soup = BeautifulSoup(html, "html.parser") restaurants = [] cards = soup.select('div[data-qa="restaurant-card"]') for card in cards: try: anchor = card.select_one("a[href]") link = BASE + anchor["href"] if anchor else "" restaurants.append({ "name": text_of(card, 'div[data-qa="restaurant-info-name"]'), "cuisine": text_of(card, 'div[data-qa="restaurant-cuisine"]'), "rating": text_of(card, 'div[data-qa="restaurant-ratings"]'), "link": link, }) except Exception as e: print(f"Skipped a card: {e}") return restaurants def export(rows, name="just_eat_restaurants"): with open(f"{name}.json", "w", encoding="utf-8") as f: json.dump(rows, f, indent=4, ensure_ascii=False) with open(f"{name}.csv", "w", newline="", encoding="utf-8") as f: writer = csv.DictWriter(f, fieldnames=FIELDS) writer.writeheader() writer.writerows(rows) print(f"Saved {len(rows)} restaurants to {name}.json and {name}.csv") def main(): url = "https://www.just-eat.co.uk/area/ec4r3tn" html = fetch_listings(url) if not html: return rows = parse_restaurants(html) export(rows) if __name__ == "__main__": main()
Запустите полный скрипт командой python just_eat_scraper.py. Он загружает отрендеренную прокрученную страницу района, парсит по одной строке на ресторан и записывает как just_eat_restaurants.json, так и just_eat_restaurants.csv. Поле link в каждой строке, это именно тот URL, который вы передаёте в скрапер меню в следующем разделе.
Как выглядит результат объявлений
Вы получаете чистый список записей ресторанов в порядке объявлений, готовых для записи в JSON, CSV или базу данных.
[ { "name": "Tower Mangal", "cuisine": "Turkish, Mediterranean", "rating": "4.5(26)", "link": "https://www.just-eat.co.uk/restaurants-tower-mangal-southwark/menu" }, { "name": "Sud Italia", "cuisine": "Pizza, Italian", "rating": "3(2)", "link": "https://www.just-eat.co.uk/restaurants-sud-italia-aldgate/menu" } ]
Шаг 5: Парсинг меню ресторана
Ссылка из объявления ведёт прямо на страницу меню ресторана, которая содержит более подробные данные: блюда, их цены и описания, сгруппированные по категориям. Страница меню также рендерится с JavaScript и пагинируется прокруткой, поэтому логика загрузки повторяет загрузку объявлений. Проверьте страницу меню тем же способом, и вы найдёте следующие элементы:
-
Категория:
<section>сdata-qa="item-category"; её название находится в<h2>сdata-qa="heading". -
Название блюда: внутри
<h2>элемента сdata-qa="heading". -
Цена блюда: внутри
<span>, класс которого начинается сformatted-currency-style. -
Описание блюда: внутри
<div>, класс которого начинается сnew-item-style_item-description.
Поскольку классы цены и описания генерируются со стабильным префиксом, парсер сопоставляет по префиксу с помощью атрибутного селектора [class^="..."], а не по полному нестабильному имени класса. Небольшой вызов re.sub убирает многократные пробелы, которые Just Eat оставляет в длинных описаниях.
import csv import json import re from crawlbase import CrawlingAPI from bs4 import BeautifulSoup api = CrawlingAPI({"token": "YOUR_CRAWLBASE_TOKEN"}) MENU_FIELDS = ["category", "name", "price", "description"] def fetch_menu_page(url): options = {"scroll": "true", "scroll_interval": "15"} response = api.get(url, options) if response["status_code"] == 200: return response["body"].decode("utf-8") print(f"Failed to fetch the menu page. Status: {response['status_code']}") return None def text_of(node, selector, default=""): el = node.select_one(selector) return el.get_text(strip=True) if el else default def parse_menu(html): soup = BeautifulSoup(html, "html.parser") menu = [] categories = soup.select('section[data-qa="item-category"]') for category in categories: category_name = text_of(category, 'h2[data-qa="heading"]', "Uncategorized") items = category.select('div[data-qa="item-category-list"] div[data-qa="item"]') for item in items: description = text_of(item, 'div[class^="new-item-style_item-description"]') menu.append({ "category": category_name, "name": text_of(item, 'h2[data-qa="heading"]'), "price": text_of(item, 'span[class^="formatted-currency-style"]'), "description": re.sub(r"\s+", " ", description), }) return menu def export_menu(rows, name="just_eat_menu"): with open(f"{name}.json", "w", encoding="utf-8") as f: json.dump(rows, f, indent=4, ensure_ascii=False) with open(f"{name}.csv", "w", newline="", encoding="utf-8") as f: writer = csv.DictWriter(f, fieldnames=MENU_FIELDS) writer.writeheader() writer.writerows(rows) print(f"Saved {len(rows)} menu items to {name}.json and {name}.csv") def main(): menu_url = "https://www.just-eat.co.uk/restaurants-tower-mangal-southwark/menu" html = fetch_menu_page(menu_url) if not html: return rows = parse_menu(html) export_menu(rows) if __name__ == "__main__": main()
Страница меню также прокручивается, поэтому fetch_menu_page использует тот же параметр scroll с более коротким scroll_interval в 15 секунд, поскольку большинство меню меньше, чем сетка ресторанов загруженного района. parse_menu проходит по каждой секции data-qa="item-category", считывает заголовок категории один раз, затем перебирает элементы внутри неё и записывает название блюда, цену и очищенное описание. Для более широкого охвата передайте в него значения link из экспорта объявлений и добавьте небольшую задержку между ресторанами, так же как и между страницами районов.
Как выглядит результат меню
Каждый пункт меню становится одной плоской записью, отмеченной своей категорией, поэтому экспорт легко загружается в таблицу или конвейер сравнения цен.
[ { "category": "What's New?", "name": "Terry's Chocolate Orange Pie", "price": "£2.49", "description": "Crispy chocolate pastry filled with a chocolate orange ganache." }, { "category": "What's New?", "name": "Large Grimace Shake", "price": "£3.99", "description": "Milkshake base blended with blueberry-flavour syrup." } ]
Масштабирование по районам и защита от блокировки
Одна страница района, это демонстрация; реальная исследовательская задача охватывает множество почтовых индексов, а затем углубляется в меню каждого ресторана. Just Eat предоставляет страницу района для каждого почтового индекса по собственному URL /area/, поэтому вы ведёте список почтовых индексов, парсите каждый район, а затем переходите по ссылке link каждого ресторана в скрапер меню. Несколько привычек помогают поддерживать работоспособность такого расширенного запуска, и они применимы к любой сложной коммерческой цели.
- Соблюдайте темп запросов. Добавьте задержку между страницами районов и между загрузками меню, вместо того чтобы отправлять всё сразу. Планируйте более тяжёлые задания на непиковые часы, чтобы снизить нагрузку на серверы сайта.
- Опирайтесь на ротацию. Пул резидентных IP распределяет запросы по многим адресам реальных пользователей, чтобы ни один из них не превысил лимит. Crawling API делает это за вас; если вы строите собственный стек, именно эта часть требует тщательной проработки.
-
Настраивайте прокрутку. Устанавливайте
scroll_intervalв соответствии с тем, насколько насыщена каждая страница, чтобы загрузить все карточки без лишней прокрутки на коротком списке. -
Сохраняйте только то, что нужно. Храните поля объявлений и меню, используемые вашим проектом, и отбрасывайте остальное. Периодически проверяйте селекторы
data-qa, чтобы скрапер успевал за изменениями разметки.
Для более широкой стратегии избежания блокировок смотрите руководство как парсить сайты, не попадая под блокировку, а для понимания важности рендеринга, материал как выполнять краулинг JavaScript-сайтов. Если вы только начинаете парсинг на Python, руководство парсинг веб-сайта с помощью Python охватывает основы, а для превращения цен из меню в сравнительный канал материал веб-скрапинг для ценовой аналитики показывает, к чему ведут эти данные.
Легально ли парсить Just Eat?
Допустимость парсинга Just Eat зависит от Условий использования Just Eat, вашей юрисдикции и того, что вы делаете с данными. Условия Just Eat ограничивают автоматический доступ, поэтому парсинг может противоречить этим условиям вне зависимости от тщательности вашего инструментария. Ни один код в этом руководстве не меняет этого; он лишь обеспечивает техническую сторону. Прочитайте Условия использования Just Eat и его robots.txt, и воспринимайте оба документа как границы того, что вы собираете. Для коммерческого или конкурентного использования правовая картина становится сложнее, и консультация с юристом по вашему конкретному случаю является разумным шагом.
Несколько правил, которых стоит придерживаться. Собирайте только публичные данные: названия ресторанов, кухни, рейтинги, ссылки на объявления и пункты меню, которые любой пользователь видит на странице района или меню без аккаунта. Поддерживайте объём запросов достаточно низким, чтобы не перегружать серверы Just Eat, и избегайте персональных данных, включая всё, связанное с идентифицируемыми клиентами, рецензентами или именованными лицами, кроме того, что публично указано. Описания блюд и фотографии в меню являются собственным авторским контентом ресторана, поэтому не публикуйте их полностью, как если бы они были вашими.
Это руководство намеренно ограничено публичными страницами районов и меню, поскольку это граница, которая делает работу обоснованной. Оно не охватывает ничего за входом в систему, историю аккаунтов или заказов, платёжные данные или попытки обойти аутентификацию или CAPTCHA, к которой у вас нет права доступа. Если вашему проекту нужно больше, чем публичные данные объявлений, или гарантированная структура и коммерческие права, официальное партнёрство или соглашение об обмене данными с Just Eat является правильным путём, а не более изощрённый скрапер.
Ключевые выводы
-
Страницы районов Just Eat, публичный каталог ресторанов. Каждая страница
/area/перечисляет, кто доставляет в данном почтовом индексе, с именем, кухней, рейтингом и ссылкой, именно поэтому она полезна для исследования местных рынков питания. - Вам нужны рендеринг и доверенный IP вместе. Just Eat заполняет свою сетку на стороне клиента и блокирует трафик ботов, поэтому Crawling API рендерит страницу за резидентным IP в одном вызове.
-
Опирайтесь на селекторы
data-qa. Обходите карточкиdata-qa="restaurant-card"для объявлений и секцииdata-qa="item-category"для меню; эти тестовые атрибуты надёжнее генерируемых имён классов, но всё равно могут измениться. -
Управляйте бесконечной прокруткой через API. Передавайте
scrollиscroll_intervalвместо самостоятельного управления прокруткой и настраивайте интервал в зависимости от насыщенности страницы. - Оставайтесь в рамках публичных данных. Соблюдайте Условия использования и robots.txt Just Eat, избегайте аккаунтов, заказов и персональных данных, и не публикуйте авторский контент меню как свой.
Часто задаваемые вопросы
Почему обычный запрос не возвращает рестораны с Just Eat?
Just Eat рендерит свою сетку ресторанов на стороне клиента и загружает больше карточек при прокрутке, поэтому обычный запрос часто получает пустую оболочку. Помимо этого, сайт проверяет или блокирует трафик, не похожий на запросы реального браузера. Рендеринг страницы через Crawling API за доверенным IP с включённой опцией прокрутки решает обе проблемы, именно поэтому скрапер здесь маршрутизирует запрос через него.
Как парсить Just Eat для конкретного района?
Каждый район Just Eat имеет собственный стабильный URL /area/, привязанный к почтовому индексу, например /area/ec4r3tn для района London Bridge. Укажите скраперу нужный URL района. Для охвата многих районов ведите список почтовых индексов и перебирайте их URL, добавляя небольшую задержку между запросами.
Можно ли извлечь информацию о меню конкретных ресторанов?
Да. Поле link каждого объявления ведёт прямо на страницу меню ресторана. Передайте этот URL в скрапер меню, чтобы извлечь название блюда, цену и описание, сгруппированные по категории. Страница меню рендерится с JavaScript и пагинируется прокруткой, так же как страница района, поэтому та же опция scroll загружает полное меню перед парсингом.
Как скрапер обрабатывает бесконечную прокрутку Just Eat?
Just Eat использует пагинацию на основе прокрутки, а не пронумерованные страницы. Вместо того чтобы автоматизировать прокрутку самостоятельно, передайте scroll: "true" и значение scroll_interval в секундах в Crawling API, и он прокрутит страницу на стороне сервера до истечения интервала, а затем вернёт полностью загруженный HTML. Увеличивайте интервал для более насыщенных районов и уменьшайте для коротких меню.
Почему использовать селекторы data-qa вместо имён классов?
Just Eat генерирует утилитарные имена классов, которые меняются без предупреждения, в то время как его атрибуты data-qa существуют для собственного автоматизированного тестирования сайта и остаются более стабильными между релизами. Нацеливание на data-qa="restaurant-card" или data-qa="item-category" даёт более надёжный хук. Для цены и описания, использующих генерируемые классы с фиксированным префиксом, парсер сопоставляет по этому префиксу с помощью селектора [class^="..."].
Как избежать блокировки при парсинге Just Eat?
Поддерживайте низкую частоту запросов с одного IP, добавьте задержку между загрузками районов и меню и используйте ротацию резидентных IP, чтобы ни один адрес не превысил лимит. Crawling API управляет ротацией, пулом доверенных IP и обработкой CAPTCHA за вас; если вы строите собственный стек, именно в эту часть стоит инвестировать. Следите за кодами статуса и снижайте темп, когда начинают появляться проверки.
Обходите любой сайт в масштабе, без борьбы с инфраструктурой.
Crawlbase берёт на себя прокси, отпечатки и CAPTCHA, чтобы ваша команда выпускала конвейеры данных вместо поддержки обвязки краулинга. 1 000 запросов бесплатно, без карты.
