ГлавнаяБлогМасштабирование парсинга: ошибки и решения на миллионах страниц
Python

Масштабирование парсинга: ошибки и решения на миллионах страниц

Узнайте, как масштабировать парсинг до миллионов страниц в день: очереди, ретраи, дедупликация, парсинг и отладка. Практические советы с кодом на Python.

Al
Редакция Algolitalgolit.ru
10 мин чтения23 июля 2026 г.

Почему парсинг на масштабе — это не про парсинг

Когда вы обрабатываете миллионы страниц в день, сам код извлечения данных — лишь малая часть системы. Настоящие проблемы возникают вокруг него: очереди, ретраи, дедупликация, парсинг и отладка. В этой статье я расскажу, что ломалось в моей платформе, которая обрабатывала миллионы страниц с 95% успешностью, и как мы это чинили.

Очередь без тормозов — это свалка

Краулинг работает рывками: одна категория порождает сотни URL, а обновление sitemap вываливает полмиллиона сразу. Ваши парсеры работают равномерно, но очередь должна уметь сказать «нет». Первая наша очередь была безграничной — Redis потреблял память два дня, а потом всё падало разом. Решение: ограничьте очередь, заставьте продюсеров блокироваться или сбрасывать задачи при заполнении. Пауза в краулинге на час — не проблема, а потеря брокера — выходные.

Ретраи, которые устраивают DDoS

Когда целевой сайт отвечает 500, все неудачные страницы попадают в ретрай с фиксированной задержкой. 40 000 страниц атакуют сайт в одном окне — он падает снова, и теперь его WAF вас запомнил. Решение: full jitter на backoff и circuit breaker на домен.

import random

def backoff(attempt, base=2.0, cap=300.0):
    # full jitter: равномерно размазываем ретраи по окну
    return random.uniform(0, min(cap, base * 2 ** attempt))

Эта однострочная функция — разница между вежливыми ретраями и случайным DDoS.

Дедупликация до загрузки, а не после

Один и тот же товар приходит по шести разным URL (трекинг, параметры цвета, разные категории). Если дедуплицировать после загрузки, вы платите за шесть запросов ради одной страницы. Канонизируйте URL при постановке в очередь: удалите мусорные параметры, приведите к единому виду, проверьте seen-set. И не забудьте про TTL или bloom-фильтр для seen-set — он растёт бесконечно.

Тихий дрейф парсера

Сайты редко ломают парсер громко. Цена переезжает из DOM в JSON-блоб, атрибут изображения переименовывается. Извлечение «успешно», но одно поле становится null на 30% страниц, и никто не замечает до понедельника. Спасает мониторинг fill-rate: для каждого поля отслеживайте долю страниц с успешным извлечением, стройте скользящий базовый уровень и alert на дельту. Зелёный прогон доказывает только то, что код не упал.

Второй секрет 95%: никогда не полагайтесь на одну стратегию извлечения. Embedded JSON, микроданные, DOM-селекторы — запускайте несколько и объединяйте по уверенности. Когда редизайн убивает одну, остальные поддерживают данные.

CPU-узкое место в I/O-системе

Парсинг кажется I/O-задачей: загрузка, ожидание, загрузка. Вы строите async-систему, но профилирование показывает, что узкое место — парсинг HTML. Загрузка страницы в парсер и извлечение данных — CPU-интенсивная синхронная операция. В однопоточном runtime каждый парсинг блокирует event loop, а значит, блокирует загрузки. Конкурентность выглядит здоровой, а пропускная способность — нет, потому что воркеры ждут друг друга, а не сеть.

Решение: вынести тяжёлый парсинг в пул воркеров, а при ошибке падать на inline-парсинг. Загрузки продолжаются, пока парсинг идёт в другом месте. Это дало один из самых больших приростов пропускной способности.

Отладка прошлого

Самые неприятные вопросы приходят поздно: «Почему цены бренда X пропали 14-го?» Сегодня 19-е, страницы изменились, логи говорят, что всё было хорошо. Мы вышли из ситуации с помощью типизированного потока событий на страницу и архивации сырого HTML. Каждая страница порождала структурированные события (fetched, parsed, extracted), а сырой ответ сохранялся. Чтобы понять, что было 14-го, мы повторно запускали текущий парсер на архивных страницах и сравнивали вывод. Отладка в прошедшем времени — без неё вы восстанавливаете инциденты по ощущениям.

Практический вывод

Ничего из этого не гламурно. Нет умных алгоритмов. В малом масштабе парсинг — это задача извлечения. На миллионах страниц в день — это задача распределённых систем в костюме парсинга: backpressure, thundering herd, тихое умирание данных, отсутствие аудита. Всё это я превращаю в продукт Cartpie — API для e-commerce данных, чтобы вам не пришлось владеть всей этой кухней. Бесплатный тариф уже работает. А вы: начните с ограничения очереди и full jitter — это спасёт вас от первых ночных звонков.

#парсинг#масштабирование#очереди#ретраи#дедупликация
Al
Редакция Algolit

Пишем про алгоритмы, подготовку к собеседованиям и карьеру в IT — так, чтобы было понятно и полезно.

Хочешь закрепить знания на практике?

Решай задачи на Algolit — интерактивная платформа для обучения

Начать бесплатно →