Если вы парсите Wildberries, Ozon или любой другой сайт через загрузку полных HTML-страниц, вы платите за трафик прокси в 5-10 раз больше, чем могли бы. Каждая страница карточки товара — это 200-800 КБ разметки, скриптов и стилей, из которых вам нужны буквально несколько полей: цена, наличие, рейтинг. В этой статье разбираем, как найти скрытый API сайта и получать те же данные напрямую, в компактном JSON-формате.
Почему парсинг HTML съедает трафик прокси
Когда парсер загружает страницу через обычный HTTP-запрос или через headless-браузер (Selenium, Puppeteer, Playwright), сервер отдаёт полный HTML-документ: разметку, инлайн-скрипты, стили, иногда base64-изображения и сотни строк JSON с данными для рекламных виджетов, которые вам не нужны. Средняя карточка товара на Wildberries весит 300-600 КБ, на Ozon — до 800 КБ, если считать все связанные ресурсы (CSS, шрифты, трекеры).
Если вы мониторите 10 000 товаров раз в день через 3 прокси-сессии, это легко выливается в десятки гигабайт трафика в месяц. Резидентные и мобильные прокси обычно продаются по трафику, поэтому каждая лишняя мегабайта — это прямые расходы. При этом реальные данные, которые вам нужны — цена, скидка, остаток на складе, рейтинг — занимают в JSON-ответе 1-5 КБ. Разница в 100-200 раз по объёму на один товар, а с учётом накладных расходов на рендеринг браузера — экономия по времени и CPU получается ещё больше.
Дополнительная проблема HTML-парсинга — хрупкость. Сайты маркетплейсов регулярно меняют вёрстку, классы CSS, структуру DOM. Каждое такое изменение ломает парсер, построенный на XPath или CSS-селекторах. Внутренний API меняется гораздо реже, потому что от него зависит работа мобильного приложения и фронтенда сайта одновременно.
Что такое скрытый API и откуда он берётся
Почти каждый современный сайт — это SPA (Single Page Application) или гибридное приложение, где браузер сначала загружает "скелет" страницы, а затем через JavaScript делает дополнительные запросы к внутреннему API за реальными данными: ценами, остатками, отзывами, рекомендациями. Эти запросы называют скрытыми или внутренними API — они не документированы публично, но полностью открыты в трафике браузера.
Технически это обычно REST или GraphQL эндпоинты, которые отдают данные в формате JSON. Например, у Wildberries карточка товара подгружается через запросы вида card.wb.ru и wbx-content-v2.wbstatic.net, а цены и остатки идут отдельным запросом на basket-01.wb.ru и похожие домены. У Ozon аналогичная логика: фронтенд ходит к внутреннему composer API, который агрегирует данные из микросервисов.
Важно понимать: использование такого API формально не является взломом — вы просто повторяете те же запросы, которые делает обычный браузер пользователя. Но сайты защищают эти эндпоинты через антибот-системы, поэтому дальше нужна аккуратная имитация поведения реального клиента, в том числе через качественные прокси.
Как найти скрытый API через DevTools
Найти внутренний API можно без единой строчки кода, используя встроенные инструменты браузера Chrome или Firefox. Вот пошаговый алгоритм:
- Откройте нужную страницу товара в Chrome, нажмите F12 и перейдите на вкладку Network.
- В фильтре запросов выберите тип Fetch/XHR — так вы отсечёте загрузку картинок, шрифтов и статики.
- Обновите страницу (F5) и посмотрите список запросов, которые появились после загрузки скелета страницы.
- Найдите запрос, в ответе которого (вкладка Response) видна цена товара, название или другие нужные поля в формате JSON.
- Кликните на этот запрос и скопируйте его как cURL (правой кнопкой → Copy → Copy as cURL) — это даст вам полный набор заголовков, кук и параметров.
- Проверьте, какие параметры в URL обязательны (артикул товара, регион, версия API), а какие можно убрать без потери данных.
После этого достаточно повторить этот запрос через обычную HTTP-библиотеку, подставляя нужный артикул или ID товара вместо того, чтобы рендерить всю страницу целиком. Это работает для большинства маркетплейсов — Wildberries, Ozon, Avito, а также для многих зарубежных площадок вроде Amazon и eBay.
Сравнение трафика: HTML vs JSON API
Разница в объёме данных настолько велика, что стоит показать её в цифрах. Ниже — усреднённые замеры для одной карточки товара на популярных маркетплейсах.
| Способ парсинга | Средний размер ответа | Время загрузки | Нужен рендеринг JS |
|---|---|---|---|
| Полный HTML через Selenium | 400-800 КБ | 1.5-4 сек | Да |
| Простой HTTP-запрос (requests) | 150-300 КБ | 0.3-0.8 сек | Нет |
| Скрытый JSON API | 3-15 КБ | 0.1-0.3 сек | Нет |
При мониторинге 50 000 товаров в день переход с headless-браузера на прямые запросы к API сокращает трафик с примерно 30-40 ГБ до 300-700 МБ в месяц. Это не только экономия на прокси-трафике, но и снижение нагрузки на серверную инфраструктуру парсера — меньше CPU на рендеринг, меньше памяти, быстрее сбор данных.
Практический пример на Python
Рассмотрим упрощённый пример: получение цены и остатка товара через прямой запрос к внутреннему API вместо загрузки полной страницы. Это учебный шаблон — точные эндпоинты и параметры нужно определять через DevTools для конкретного сайта, так как структура запросов может отличаться в зависимости от региона и версии API.
import requests
def get_product_data(product_id: str, proxies: dict = None) -> dict:
"""
Получает данные товара через внутренний API вместо полного HTML.
proxies — словарь с прокси в формате requests: {"http": "...", "https": "..."}
"""
url = f"https://card.example-marketplace.ru/v2/detail"
params = {
"nm": product_id,
"dest": "-1257786", # регион, определяется через DevTools
"spp": "0"
}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/120.0 Safari/537.36",
"Accept": "application/json",
"Referer": f"https://www.example-marketplace.ru/catalog/{product_id}/detail.aspx"
}
response = requests.get(
url,
params=params,
headers=headers,
proxies=proxies,
timeout=10
)
response.raise_for_status()
data = response.json()
product = data["products"][0]
return {
"id": product["id"],
"name": product["name"],
"price": product["salePriceU"] / 100,
"stock": product.get("totalQuantity", 0),
"rating": product.get("reviewRating", None)
}
if __name__ == "__main__":
proxy = {
"http": "http://user:pass@proxy-host:port",
"https": "http://user:pass@proxy-host:port"
}
result = get_product_data("123456789", proxies=proxy)
print(result)
Обратите внимание на три момента в этом примере. Во-первых, мы указываем заголовок Referer, потому что многие API проверяют, что запрос пришёл "из браузера", а не напрямую по URL. Во-вторых, мы используем реалистичный User-Agent, а не дефолтный от библиотеки requests, который легко детектируется. В-третьих, весь запрос укладывается в один HTTP-вызов без рендеринга — это то, что даёт кратный выигрыш по трафику и скорости.
Для GraphQL-эндпоинтов логика аналогична, но вместо GET-параметров вы отправляете POST-запрос с телом-запросом в формате JSON, где явно перечисляете нужные поля — это ещё больше сокращает объём ответа, так как сервер отдаёт только запрошенные данные.
Работа с прокси при запросах к API
Даже при переходе на компактный JSON-формат вам всё равно нужны прокси — маркетплейсы ограничивают количество запросов с одного IP и банят при аномальной активности. Правильный выбор типа прокси здесь напрямую влияет на стабильность парсера.
Для массового обхода API маркетплейсов вроде Wildberries или Ozon хорошо подходят прокси дата-центров — они дают высокую скорость и низкую стоимость трафика, что критично при частых запросах к легковесным JSON-эндпоинтам. Но если конкретный API защищён более жёстким антиботом и банит датацентровые подсети целиком, разумнее переключиться на резидентные прокси — они используют реальные IP-адреса домашних пользователей и реже попадают под блокировку по подсети.
Для API, которые завязаны на мобильные приложения (некоторые версии эндпоинтов Avito или маркетплейсов отдают данные только по мобильному трафику), может потребоваться подключение через мобильные прокси — они имитируют трафик реальных операторов сотовой связи и проходят проверки, которые блокируют обычные IP.
При настройке прокси в парсере важно также разносить запросы по времени и использовать ротацию IP — даже компактный JSON-запрос, повторённый 1000 раз в минуту с одного адреса, вызовет подозрение у системы защиты. Настройте пул из нескольких прокси-сессий и распределяйте нагрузку между ними, добавляя случайные задержки в 1-3 секунды между запросами.
Подводные камни: токены, подписи, антибот
Скрытые API далеко не всегда открыты нараспашку. Часть сайтов защищает свои эндпоинты дополнительными механизмами, которые нужно учитывать при построении парсера.
- Временные токены сессии — некоторые API требуют предварительный запрос за токеном, который затем передаётся в заголовке следующих запросов и живёт ограниченное время (обычно 5-30 минут).
- Подпись запроса (signature) — параметры запроса хешируются на клиенте с секретным ключом из JS-кода страницы. Такую подпись нужно либо воспроизводить вручную, разобрав алгоритм, либо выполнять через headless-браузер только на этапе получения токена, а дальше слать лёгкие запросы напрямую.
- Rate limiting по IP и по User-Agent — при превышении частоты запросов сайт временно блокирует доступ. Решается ротацией прокси и разумными задержками.
- Fingerprinting заголовков — некоторые системы проверяют полный набор заголовков (порядок, наличие Accept-Language, Sec-Fetch-*) и блокируют запросы с "неполным" набором, характерным для скриптов, а не браузеров.
- Гео-зависимость данных — цены и остатки на маркетплейсах могут отличаться по регионам, поэтому важно передавать корректный параметр региона/склада в запросе, иначе данные будут нерелевантны.
Если API закрыт подписью запроса, которую сложно воспроизвести, компромиссный вариант — использовать headless-браузер (Playwright, Puppeteer) только для перехвата сетевых запросов и извлечения готового JSON-ответа, без парсинга DOM. Это медленнее прямого HTTP-запроса, но всё ещё быстрее и легче, чем полноценный парсинг вёрстки страницы.
Чек-лист перед запуском парсера на скрытом API
- Найден эндпоинт через DevTools, скопирован как cURL и протестирован в Postman или через requests.
- Определены обязательные параметры запроса (ID товара, регион, версия API) и исключены избыточные.
- Заголовки User-Agent, Referer и Accept-Language настроены реалистично.
- Проверено, требуется ли токен сессии или подпись запроса, и продуман способ их получения.
- Настроена ротация прокси и случайные задержки между запросами.
- Выбран подходящий тип прокси под конкретную защиту сайта — датацентр, резидентные или мобильные.
- Добавлена обработка ошибок 429 и 403 с автоматическим переключением на другой прокси.
- Настроено логирование объёма трафика для контроля реальной экономии.
Заключение
Переход от парсинга полного HTML к работе со скрытым API — это не просто техническая оптимизация, а прямое снижение расходов на прокси-трафик и инфраструктуру. Вместо загрузки сотен килобайт лишней разметки вы получаете компактный JSON с ровно теми полями, которые нужны для мониторинга цен, остатков или рейтингов. Дополнительный бонус — устойчивость парсера к изменениям вёрстки сайта, так как внутренние API меняются реже фронтенда.
При этом сама методика поиска API не отменяет необходимость в качественных прокси — антибот-системы маркетплейсов одинаково внимательно следят и за HTML-запросами, и за обращениями к JSON-эндпоинтам. Если вы мониторите Wildberries или Ozon в больших объёмах, начните с быстрых прокси дата-центров для снижения затрат, а при первых признаках блокировок переключайтесь на резидентные или мобильные пулы IP для более стабильной работы парсера.