← Назад к блогу

Скрытый JSON API сайта: как найти внутренние эндпоинты и урезать трафик парсера

Сайт сам отдаёт себе данные в JSON — и этот ответ в десятки раз легче HTML-страницы. Разбираем по шагам, как найти внутренний эндпоинт в DevTools, почему скопированный cURL работает, а ваш код нет, что делать с токенами и пагинацией, и когда от идеи лучше отказаться.

📅22 сентября 2026 г.
Скрытый JSON API сайта: как найти внутренние эндпоинты и урезать трафик парсера

Парсер тянет 400 КБ HTML ради восьми полей, которые сайт сам себе отдаёт в JSON-ответе на 8 КБ. Разница в пятьдесят раз — это не про «красивый код», это про счёт за резидентные прокси, где вы платите за каждый гигабайт. Разбираем, как найти внутренний API сайта, что в 2026 году мешает его повторить, и когда от этой идеи стоит отказаться.

Зачем искать скрытый API, если HTML уже парсится

Почти любой современный интерфейс — React, Vue, Angular, Next.js — сначала грузит каркас страницы, а данные подтягивает отдельными запросами к собственным эндпоинтам. Эти эндпоинты не документированы, но они существуют, отвечают чистым JSON и доступны без headless-браузера.

Что вы получаете, перейдя на них:

  • Трафик падает на порядок. На разборе типичной товарной выдачи HTML-страница весит около 400 КБ вместе с разметкой, стилями и трекерами, а соответствующий JSON-эндпоинт — примерно 8 КБ, причём полей в нём больше: внутренние ID, остатки, варианты товара.
  • Не нужен браузер. Уходит рендеринг JavaScript, а с ним — память, процессор и десятки дополнительных запросов за шрифтами и аналитикой.
  • Данные уже структурированы. Никаких селекторов, которые ломаются от смены CSS-класса.
  • Меньше запросов — меньше поводов для бана. Отрисовка одной страницы каталога в браузере — это десятки обращений к сайту; тот же объём данных через API — одно.

Для проекта на резидентных прокси это прямая экономия: тариф считается по гигабайтам, и переход с рендеринга на JSON обычно сжимает счёт сильнее, чем любые ухищрения с блокировкой картинок. Смежная тема — как сократить трафик парсера в 5 раз остальными методами.

Пошагово: как найти эндпоинт

  1. Сначала проверьте, нет ли официального API. Загляните на /developers, /api, /docs целевого сайта. Публичный документированный API версионируется и предупреждает о депрекациях — приватный меняется молча.
  2. Откройте DevTools (F12) и перейдите на вкладку Network, убедившись, что запись включена.
  3. Включите фильтр Fetch/XHR. Он отсекает картинки, шрифты и аналитику, оставляя только обращения за данными.
  4. Очистите список, чтобы убрать шум первичной загрузки.
  5. Спровоцируйте нужные данные: пролистайте выдачу, нажмите «следующая страница», примените фильтр, откройте карточку. Интересующий вас запрос появится в момент действия.
  6. Найдите ответ с вашими данными. Самый быстрый способ — Ctrl+F по панели Network: ищите уникальное значение, которое видите на экране (артикул, точную цену, кусок имени), и смотрите, какой запрос его породил.
  7. Скопируйте запрос целиком: правый клик по строке → Copy → Copy as cURL. Дальше конвертируйте в код через curlconverter — так вы не потеряете ни одного заголовка.

Характерные пути, на которые стоит смотреть в первую очередь: /api/, /v1/, /v2/, /search, /products, /listings, /graphql.

Особый случай: сайты на Next.js

Здесь данные часто вообще не требуют отдельного запроса — они лежат прямо в HTML. На старом Pages Router это блок __NEXT_DATA__. На App Router (Next.js 13 и новее) данные для гидратации разложены по вызовам self.__next_f.push() в нескольких script-узлах — это сериализованный payload React Server Components. Разбирать его руками неприятно: чанки ссылаются друг на друга через $-префиксы и могут быть разрезаны посреди строки. Для Python есть библиотека nextflight, которая парсит и Flight-payload из HTML, и сырой RSC-ответ (запрос с заголовком RSC: 1), а искать в нём предлагает по именам ключей, а не по индексам массива — так парсер переживает передеплой сайта.

Реверс параметров: пагинация и фильтры

Найденный эндпоинт почти всегда параметризован. Встречаются три схемы:

  • По страницам: ?page=3&per_page=20
  • Смещение и лимит: ?offset=40&limit=20
  • Курсор: ?after=<token>&limit=20 — токен следующей страницы приходит в теле предыдущего ответа

Три правила, которые экономят часы отладки:

  • Останавливайтесь на пустой пачке, а не на заранее вычисленном числе страниц: счётчик total в приватных API врёт чаще, чем хотелось бы.
  • Проверяйте фактический размер пачки. Запросили 100, пришло 20 — значит, у эндпоинта свой потолок, и ваша арифметика по страницам уже неверна.
  • Не лезьте на страницу 500. Глубокая пагинация почти везде обрезается сервером; вместо неё режьте выборку фильтрами — по категории, по диапазону цен, по дате.

Почему cURL из браузера работает, а ваш код — нет

Это самая частая точка провала, и причина почти всегда одна: потерянный заголовок. Скопированный cURL несёт весь контекст запроса, а самописный клиент — нет.

Что обычно оказывается обязательным:

  • Кастомные заголовки с префиксом X- — X-CSRF-Token, X-Requested-With: XMLHttpRequest и всевозможные X-*-Token, которые фронтенд подставляет сам. Без них вы получите ответ из диапазона 400–500.
  • Referer — контекстный заголовок, который генерируется действием пользователя. Многие эндпоинты проверяют, что запрос «пришёл со своей страницы».
  • Authorization: Bearer <JWT> — короткоживущий токен, обычно на 15–60 минут. Хардкодить его бессмысленно: нужно уметь получать свежий.
  • Сессионные cookie — держите их в объекте сессии, а не копируйте руками.
  • Корректный Content-Type для POST: application/json и application/x-www-form-urlencoded кодируют тело по-разному, и несовпадение с объявленным типом ломает запрос молча.

Где искать сами токены, если они не в cookie: в HTML-исходнике внутри <script> (поиск по известному значению через Ctrl+F), в бандлах JavaScript, в localStorage или IndexedDB — вкладка Application в DevTools.

Подводные камни, о которых узнают поздно

Приватный API меняется без предупреждения. У него нет версионирования, обещаний совместимости и поддержки: команда фронтенда переименовывает поле в четверг вечером, и ваш парсер собирает пустоту. Защита — не «надёжный селектор», а контроль структуры: проверяйте, что обязательные поля на месте и нужного типа; следите за долей пустых значений и количеством записей в прогоне; пропускайте битые записи, но поднимайте тревогу, если брак превысил 10%; храните сырые ответы, чтобы потом было с чем сравнить.

API иногда защищён жёстче, чем страница. Встречается регулярно: HTML отдаётся спокойно, а на /api/ висит антибот, который проверяет и фингерпринт TLS, и связку заголовков. Тогда экономия трафика оборачивается ростом доли неуспешных запросов, и выигрыш съедается.

Подписанные запросы. Если в параметрах видно что-то вроде sign, hash или _s, фронтенд считает подпись в JavaScript. Воспроизводить её — отдельный проект, и часто дешевле остаться на HTML.

Ограничения по частоте. Приватные эндпоинты не рассчитаны на поток: держите 1–2 запроса в секунду, ставьте раздельные таймауты на соединение и чтение (например, 5 и 30 секунд), повторяйте только транзиентные ошибки — 429, 500, 502, 503, 504 — и не трогайте 401 и 404. Экспоненциальная задержка с джиттером обязательна, иначе все воркеры пойдут на второй круг одновременно. Подробнее — в разборе таймаутов и retry-логики для прокси.

Юридическая рамка. Публичные неаутентифицированные эндпоинты — одна ситуация, вход в аккаунт — принципиально другая: регистрация означает принятие пользовательского соглашения. Персональные данные подпадают под GDPR независимо от того, насколько легко они достаются. Факты — цены, характеристики, наличие — авторским правом не защищены, в отличие от текстов и изображений.

Когда остаться на HTML

Скрытый API — не всегда выигрыш. Оставайтесь на разборе страниц, если:

  • сайт серверный и никакого внутреннего API попросту нет;
  • эндпоинт требует подписи или ротации токенов — поддерживать его дороже, чем страницу;
  • на API стоит более злая защита, чем на публичных страницах;
  • нужен именно итоговый результат, который фронтенд собирает из нескольких источников;
  • вы ведёте десятки сайтов: единый HTML-конвейер масштабируется лучше, чем зоопарк приватных API с индивидуальными причудами.

Какой тип прокси брать под API-парсинг

Переход на JSON меняет расчёт, потому что смещается узкое место: трафика становится мало, а требований к качеству IP и к стабильности сессии — больше.

  • Открытый эндпоинт без авторизации и без антибота. Здесь хватает датацентр-прокси: объём данных маленький, платить за резидентные незачем.
  • Эндпоинт за антиботом или с привязкой к сессии. Нужны резидентные прокси с липкой сессией: токен, cookie и IP должны совпадать на всём протяжении цепочки, иначе сервер сбросит сессию на втором запросе. При этом счёт останется скромным — гигабайты в JSON-режиме расходуются медленно.
  • Данные из мобильного приложения. Если веб-версия закрыта, а приложение отдаёт то же самое проще, эндпоинты ищут через перехват трафика — это отдельная процедура, разобранная в статье про поиск скрытого API мобильного приложения через mitmproxy.

Коротко

Двадцать минут в DevTools часто заменяют дни борьбы с headless-браузером: фильтр Fetch/XHR, поиск по видимому значению, Copy as cURL — и у вас на руках рабочий запрос. Дальше решают детали: перенести все заголовки, разобрать схему пагинации, поставить валидацию ответа и трезво оценить, не защищён ли эндпоинт злее самой страницы. Там, где приватный API работает, он снижает и объём трафика, и число запросов — то есть сразу и стоимость прокси, и вероятность бана.