Каждый, кому нужны данные из Instagram, писал такой скрипт: curl, регулярка, чтобы вытащить JSON из HTML, json_decode, готово. Во вторник после обеда работает. В четверг — пустой массив. Добавляешь User-Agent — работает неделю. Потом выскакивает стена логина. Добавляешь прокси. А затем ключ edge_owner_to_timeline_media переименовывается во что-то другое, и foreach валится на null.
Я делал так три раза, прежде чем признать: проблема не в скрейпере. Я относился к нестабильному, мутирующему, ограниченному по лимитам источнику как к локальной базе данных. Каждое решение, принятое после этой ошибки, было неверным.
Четыре типа отказов
Сбор данных из соцсетей падает четырьмя разными способами. Их нужно различать, потому что каждому нужна своя реакция.
| Тип отказа | Проявление | Правильная реакция |
|---|---|---|
| Транзиентный | Таймаут, 502, сброс соединения | Ретрай с экспоненциальным бэкоффом |
| Rate/блок | 429 или 200 с пустым телом | Сильный бэкофф или другой маршрут |
| Изменение схемы | 200, валидный JSON, но нужное поле переместилось или исчезло | Ретрай бесполезен. Нужна валидация контракта и сигнал тревоги |
| Семантическое отсутствие | Аккаунт закрыт, удален или ноль постов | Корректный постоянный пустой ответ, без ретраев |
Первый тип — единственный, который стоит повторять. Остальные три — разные болезни, и лечить их одинаково нельзя. Особенно коварен третий: он не бросает исключение, а молча пишет null в базу. Три недели никто не замечает.
Архитектура: три стадии
Пайплайн выглядит просто: планировщик, воркеры загрузки, нормализатор, хранилище. Но главное — три правила, которые держат эту конструкцию на плаву.
- Fetch-стадия никогда не пишет в доменные таблицы. Только сырые ответы. Нормализация — отдельный, воспроизводимый шаг.
- Планировщик владеет бюджетом. Будь то кредиты API, трафик прокси или ваша готовность получать баны, один компонент решает, сколько потратить. Не воркеры. Иначе они сожрут всё за девяносто секунд.
- Нормализатор владеет контрактом. Он проверяет ответ на соответствие ожидаемой форме и громко падает при расхождении. Это будильник на случай изменения схемы.
Первое правило пропускают чаще всего. Хранение сырого ответа стоит несколько килобайт, зато если через полгода вы поймёте, что неправильно считали вовлечённость, вы перепарсите историю без единого нового запроса и без единого потраченного кредита.
Стадия 1: воркер загрузки
В воркере три проверки. Есть ли бюджет — если нет, возвращаем «deferred». Статус ответа: 404 значит «аккаунт не существует», ретраить бессмысленно. 429 или 503 — нас притормозили, возвращаем кредит в бюджет и спим долго, с джиттером. 200 — возвращаем сырое тело, без разбора. Парсинг — это забота нормализатора.
Джиттер — не блажь. Если двадцать воркеров упали одновременно и будут ретраить одновременно, они снова упадут вместе. Случайная задержка разводит их по времени.
Типичные ошибки
Обрабатывать только транзиентные сбои. Таймаут повторить можно, но что делать с блоком, изменением схемы или отсутствием аккаунта? Если всё это падает в общий catch и помечается как «ошибка», пайплайн тихо деградирует и пишет мусор.
Не сохранять сырые ответы. Если вы сразу пишете распарсенные данные, то при изменении логики парсинга придётся перезапрашивать всё снаружи, платить снова и рисковать баном.
Позволять воркерам самим решать, сколько запросов делать. Это верный способ сжечь бюджет за минуту. Бюджет должен быть один, и он должен быть в планировщике.
Скрейпер ломается не потому, что Instagram коварен. Он ломается потому, что вы проектируете его как локальный вызов. Четыре типа отказов нельзя обрабатывать одним способом. Разделите пайплайн, храните сырые ответы, централизуйте бюджет. И тогда он будет работать не 48 часов, а месяцами.
Комментарии (0)
Войдите, чтобы комментировать.
Пока нет комментариев. Будьте первым.