Надёжный веб-скрейпер на Python: архитектура и лимиты
Как построить Python-скрейпер с httpx и Pydantic: лимиты, обработка ошибок, кэш, очереди и контролируемое масштабирование.
Команда InfraProxy
21 февраля 2026 г.
Почему связка requests + BeautifulSoup больше не работает в 2026 году
Классический стек — requests для HTTP и BeautifulSoup для парсинга HTML — десятилетиями использовался для сбора данных. Сегодня он перестаёт быть достаточным для большинства коммерчески значимых источников.
Проблема 1: сетевые ответы. Источник может вернуть 403, 429 или 503. Эти статусы нужно сохранять отдельно от сетевых ошибок и обрабатывать ограниченным backoff.
Проблема 2: JavaScript. Большая часть современного контента рендерится в браузере. Запрос через requests возвращает пустой или неполный HTML — данные подгружаются через XHR/Fetch после выполнения скриптов.
Проблема 3: лимиты. Без задержек, кэша и ограниченной параллельности клиент создаёт лишнюю нагрузку и быстро получает 429.
Если источник требует CAPTCHA, входа или запрещает автоматический сбор, остановите задачу и используйте официальный API либо согласованный доступ.
Архитектура: Scraper API как сетевой слой
Scraper API — это облачный сервис, который принимает URL и возвращает готовый HTML (или структурированные данные). Внутри он использует:
- Резидентные прокси с ротацией
- JavaScript-рендеринг (Playwright/Puppeteer)
- Ограниченные повторные попытки при временных ошибках
Вы пишете простой клиент на Python: отправляете запросы к API, получаете данные, парсите их локально. Вся логика обработка ограничений инкапсулирована в сервисе.
Преимущества такого подхода:
- Быстрый старт без настройки инфраструктуры
- Предсказуемая стоимость (плата за успешный запрос)
- Единая обработка сетевых ошибок и лимитов
- Возможность сосредоточиться на бизнес-логике (извлечение, хранение, аналитика)
Настройка Python-окружения
Для работы с Scraper API достаточно стандартных библиотек HTTP и валидации данных:
# requirements.txt
httpx>=0.27.0
pydantic>=2.0.0
httpx — современная асинхронная HTTP-библиотека с поддержкой HTTP/2, совместимая с requests по интерфейсу. pydantic — для описания схем извлекаемых данных и валидации ответов.
import httpx
from pydantic import BaseModel
class ScraperClient:
def __init__(self, api_key: str, base_url: str = "https://api.example.com/v1"):
self.api_key = api_key
self.base_url = base_url
async def scrape(self, url: str, render_js: bool = True) -> str:
async with httpx.AsyncClient(timeout=60.0) as client:
resp = await client.post(
f"{self.base_url}/scrape",
json={"url": url, "render_js": render_js},
headers={"Authorization": f"Bearer {self.api_key}"}
)
resp.raise_for_status()
return resp.json()["html"]
Базовая интеграция не требует сложной логики — достаточно корректно формировать запросы и обрабатывать ответы.
Управление сетевым маршрутом
Scraper API объединяет несколько технических операций:
- Выбор прокси — подходящий тип адреса под разрешённую задачу
- JavaScript-рендеринг — получение данных, которые отсутствуют в исходном HTML
- Лимиты — ограниченная параллельность и паузы между запросами
- Диагностика — раздельный учёт HTTP-статусов и сетевых ошибок
При необходимости можно явно указать параметры:
country— геотаргетинг (например, для локальных вариантов сайта)proxy_type: "residential"— принудительное использование резидентных прокси
Для большинства задач достаточно стандартных настроек; тонкая подстройка нужна только при низком success rate.
CAPTCHA и закрытые данные
CAPTCHA — сигнал остановить автоматический сценарий и проверить правила источника. Не собирайте данные за логином или paywall. Для таких данных используйте официальный API или письменное разрешение владельца.
LLM-экстракция структурированных данных
Классический парсинг опирается на CSS/XPath-селекторы. При частых изменениях вёрстки селекторы ломаются, парсеры требуют доработки. Альтернатива — извлечение с помощью LLM: вы передаёте HTML (или текст) и схему полей, модель возвращает структурированный JSON.
class Product(BaseModel):
title: str
price: float
currency: str
in_stock: bool
# В запросе к API указываем extract_schema на основе Pydantic-модели
extract_schema = {
"title": {"type": "string"},
"price": {"type": "number"},
"currency": {"type": "string"},
"in_stock": {"type": "boolean"}
}
API, поддерживающий AI-экстракцию, принимает такую схему и возвращает готовый JSON. Преимущества: устойчивость к редизайнам, работа с неструктурированным текстом. Недостатки: выше стоимость и время ответа. Для стабильных источников CSS-селекторы остаются экономичным вариантом; LLM имеет смысл для разнородных или часто меняющихся сайтов.
Масштабирование до 10 000 страниц: асинхронный батчинг
При объёмах в тысячи страниц критична параллельность. Синхронные запросы в цикле работают слишком медленно. Необходим асинхронный подход с ограничением concurrency, чтобы не превышать лимиты API и не перегружать целевые сайты.
import asyncio
from httpx import AsyncClient, Limits
async def scrape_batch(urls: list[str], api_key: str, max_concurrent: int = 10) -> list[dict]:
limits = Limits(max_connections=20, max_keepalive_connections=10)
results = []
async def fetch_one(client: AsyncClient, url: str) -> dict | None:
try:
resp = await client.post(
"https://api.example.com/v1/scrape",
json={"url": url, "render_js": True},
headers={"Authorization": f"Bearer {api_key}"}
)
resp.raise_for_status()
return {"url": url, "html": resp.json()["html"], "status": "ok"}
except Exception as e:
return {"url": url, "error": str(e), "status": "failed"}
async with AsyncClient(timeout=60.0, limits=limits) as client:
sem = asyncio.Semaphore(max_concurrent)
async def limited_fetch(url):
async with sem:
return await fetch_one(client, url)
tasks = [limited_fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
return results
Ключевые моменты:
- Semaphore — ограничение одновременных запросов (например, 10–20)
- Connection pooling — переиспользование соединений через
AsyncClient - Обработка ошибок — логирование неудачных URL для повторной обработки
- Ретраи — экспоненциальный backoff при 429/503
При 10 000 URL и 10 параллельных запросах, при среднем времени ответа 5 секунд, полный прогон займёт ориентировочно 1–2 часа (с учётом ограничений и повторов).
Компромиссы и практические выводы
Плюсы Scraper API:
- Не нужно отдельно поддерживать прокси, браузеры и очереди
- Быстрый вывод продукта на рынок
- Предсказуемая стоимость при переменных объёмах
Минусы:
- Зависимость от провайдера
- При очень больших стабильных объёмах собственное решение с прокси может быть дешевле
- Ограничения по кастомизации (особые заголовки, сложные сценарии взаимодействия)
Гибридный подход:
- Простые, незащищённые сайты — собственный скрейпер + прокси InfraProxy
- Защищённые маркетплейсы, площадки с вакансиями, соцсети — Scraper API
- Комбинирование обоих вариантов в одном пайплайне
Для старта разумно начать с API: проверить гипотезу, оценить success rate и стоимость. При росте объёмов и стабилизации требований можно перенести часть нагрузки на DIY-решение с качественными резидентными прокси.
Перед рабочим запуском проверьте задачу на разрешённом источнике: условия теста прокси.
Этичность и ограничения
Перед сбором проверьте официальный API, robots.txt и условия использования источника. Соблюдайте Disallow и Crawl-delay, ограничивайте параллельность, используйте backoff на 429/503 и кэшируйте ответы. Собирайте только публичные данные: без обхода логина и paywall, без персональных данных и перепубликации чужих текстов. Используйте честный User-Agent и обрабатывайте запросы на удаление данных.
Нужна прокси-инфраструктура под вашу нагрузку?
Сравните Datacenter и ISP прокси, протоколы и условия теста перед договором.
Перейти к проксиЧитайте также
403, 429 и timeout: диагностика доступа к сайту
Как отличить ограничение источника от ошибки прокси: коды 403/429, timeout, TLS, Retry-After, логи и безопасный порядок проверки.
РуководстваНастройка прокси для мониторинга цен конкурентов
Пошаговое руководство по настройке прокси для мониторинга цен: ротация IP, geo-targeting, sticky-сессии, адаптация к техническим ограничениям. Код на Python и bash.
ТехническоеКак антибот-защита распознаёт автоматические запросы
Разбираем, как современные системы антибот-защиты обнаруживают скреперы: IP-репутация, TLS-отпечатки, JavaScript-челленджи, поведенческий анализ и fingerprinting устройств.