Все статьиРуководства8 мин

Скрейпинг динамических каталогов интернет-магазинов

Как собирать данные о товарах с платформ e-commerce на React: настройка JS-рендеринга, extract_schema, обход rate limits и batch-сбор каталогов 10 000+ позиций.

Команда InfraProxy

20 февраля 2026 г.

#e-commerce#динамический контент#extract_schema#React#API для скрейпинга

Почему SPA-платформы e-commerce сложно скрейпить

Многие интернет-магазины строятся на SPA (Single Page Application): React, Vue или аналогичных фреймворках. Данные о товарах загружаются через API после выполнения JavaScript. Для скрейпинга это создаёт несколько серьёзных преград.

React-рендеринг. HTML страницы изначально минимален — карточки товаров, цены, описания подгружаются асинхронно. Обычный HTTP-запрос возвращает пустой каркас с placeholder-блоками.

Стены антиботов. E-commerce-платформы защищают каталоги от парсеров: проверка TLS-отпечатков, детектирование headless-браузеров, блокировка по IP. Датацентровые запросы быстро получают 403 или CAPTCHA.

Rate limits. Ограничения на частоту запросов и подозрительные паттерны приводят к временной блокировке. Сбор больших каталогов требует ротации IP и контролируемой скорости.

Для стабильного сбора нужен API с JavaScript-рендерингом, обходом антиботов, резидентными прокси и грамотной настройкой ожидания загрузки.

Настройка запросов с JS-рендерингом для динамического контента

Базовый запрос к каталогу интернет-магазина:

import httpx
import os

API_KEY = os.environ.get("SCRAPER_API_KEY")
BASE_URL = "https://api.example.com/v1/scrape"

payload = {
    "url": "https://example.com/collections/electronics",
    "use_js_render": True,
    "js_wait_for": ".product-grid, .product-card",
    "use_residential": True
}

with httpx.Client(timeout=60.0) as client:
    resp = client.post(
        BASE_URL,
        json=payload,
        headers={
            "Authorization": f"Bearer {API_KEY}",
            "Content-Type": "application/json"
        }
    )
    resp.raise_for_status()

Параметр js_wait_for указывает селектор, по появлению которого API считает страницу готовой. Для каталогов товаров это обычно контейнер с карточками (.product-grid, .product-card). Без такого ожидания извлечение данных может произойти до завершения рендеринга, и результат будет пустым.

Извлечение структурированных данных через extract_schema

Для товарных каталогов удобно использовать extract_schema — описание целевой JSON-схемы. API извлекает данные по смыслу, а не по жёстким селекторам, что устойчивее к изменениям вёрстки:

{
  "url": "https://example.com/products/laptop-pro",
  "use_js_render": true,
  "js_wait_for": ".product-detail",
  "extract_schema": {
    "title": {"type": "string"},
    "price": {"type": "number"},
    "currency": {"type": "string"},
    "description": {"type": "string"},
    "availability": {"type": "string"},
    "variants": {
      "type": "array",
      "items": {
        "name": {"type": "string"},
        "price": {"type": "number"},
        "sku": {"type": "string"}
      }
    }
  }
}

Схема описывает, что нужно извлечь, а не как это выражено в DOM. При A/B-тестах и редизайнах такая экстракция часто остаётся рабочей дольше, чем extract_rules.

Обработка rate limits: session_id и резидентные прокси

При сборе большого каталога (сотни и тысячи страниц) rate limits становятся критичным фактором.

session_id для сессионной привязки

Используйте один и тот же session_id для всех запросов в рамках одного «сеанса» обхода каталога. API будет направлять трафик через один IP и сохранять cookies. Это снижает вероятность CAPTCHA при переходе со страницы на страницу и выглядит более естественно для антибот-системы.

payload = {
    "url": url,
    "use_js_render": True,
    "session_id": "catalog-crawl-001",
    "extract_schema": product_schema
}

Резидентные прокси

E-commerce-платформы активно блокируют датацентровые IP. Параметр use_residential: true переключает запросы на резидентные прокси — IP домашних провайдеров с высокой репутацией. Это значительно повышает success rate при большом объёме запросов.

Батчевые задачи для крупных каталогов (10K+ товаров)

При каталогах на десятки тысяч позиций последовательные запросы неэффективны. Рекомендуемый подход:

1. Генерация списка URL

Сформируйте список URL страниц товаров (из sitemap, поиска по категориям или каталога). Разбейте на батчи по 50–100 URL.

2. Асинхронный скрейпинг с ограничением concurrency

import asyncio
import httpx

async def scrape_products(urls: list[str], session_id: str, max_concurrent: int = 5) -> list[dict]:
    sem = asyncio.Semaphore(max_concurrent)

    async def fetch_one(client: httpx.AsyncClient, url: str):
        async with sem:
            payload = {
                "url": url,
                "use_js_render": True,
                "session_id": session_id,
                "use_residential": True,
                "extract_schema": product_schema
            }
            resp = await client.post(BASE_URL, json=payload, headers={"Authorization": f"Bearer {API_KEY}"})
            resp.raise_for_status()
            return resp.json().get("extract")

    async with httpx.AsyncClient(timeout=90.0) as client:
        tasks = [fetch_one(client, url) for url in urls]
        return await asyncio.gather(*tasks)

Ограничьте max_concurrent (5–10), чтобы не провоцировать rate limits. Для очень больших каталогов рассмотрите batch-эндпоинт API: отправка массива URL, получение job_id, webhook при готовности, скачивание результата.

3. Обработка ошибок и повторные попытки

Отслеживайте 429, 503 и пустые extract. Для неудачных URL реализуйте retry с экспоненциальной задержкой. Сохраняйте прогресс, чтобы при падении можно было продолжить с последнего успешного батча.

Важные нюансы

Ограничения extract_schema

extract_schema не поддерживает все типы вложенных структур. Сложные иерархии (например, произвольное количество уровней) могут потребовать комбинации с extract_rules или постобработки. Проверяйте документацию конкретного API.

VIP TLS-профили

Для особо защищённых платформ некоторые API предлагают «VIP» TLS-профили — более редкие отпечатки, реже попадающие в блокировочные списки. Если стандартный профиль даёт высокий процент отказов, рассмотрите переход на VIP.

Надёжность networkidle

Параметр ожидания networkidle (отсутствие сетевой активности) теоретически надёжнее для SPA, но на страницах с аналитикой, чатами и бесконечным скроллом сетевая активность может не прекращаться. В таких случаях предпочтите js_wait_for с селектором конкретного элемента — это даёт более предсказуемое поведение.

Резюме

  • SPA-платформы e-commerce рендерят контент через React/JavaScript — без рендеринга данные пустые
  • Включайте use_js_render и js_wait_for на контейнер с товарами
  • Используйте extract_schema для устойчивого извлечения структурированных данных о товарах
  • Обходите rate limits через session_id и резидентные прокси
  • Масштабируйте через асинхронный скрейпинг или batch API
  • Учитывайте: ограничения extract_schema, VIP TLS-профили для сложных источников, выбор между networkidle и js_wait_for

InfraProxy Scraper API поддерживает JS-рендеринг, extract_schema и резидентные прокси для сбора каталогов интернет-магазинов. Узнайте условия.

Нужны надёжные прокси для вашего проекта?

InfraProxy предоставляет серверные и резидентные прокси для российского бизнеса. Договор, постоплата, техподдержка.