AIREITER

AI-изображения

FLUX.2 ProGPT-Image 2Wan 2.7 Image ProGPT 4o ImageSeedream 5.0 ProSeedream V5 liteSeedream V4.5Еще

AI-видео

Kling 3.0 Motion ControlSora 2 ProKling 3.0 TurboSora 2Kling 3.0Grok Imagine 1.5Veo 3.1Еще

LLM

Gemini 3.6 FlashGemini 3.1 ProKimi K3Gemini 3 ProGemini 2.5 ProClaude Opus 5Claude Fable 5Еще
СкороSeedance 2.5
Super ResolutionLyric Video GeneratorGPT Image 2 1K GeneratorGPT Image 2 Product Mockup GeneratorUse GPT-5.6 Online
ДОКИ APIЦЕНЫ
БлогОбновленияLLM API GuideClaude API GuideKimi K3 API Guide
ШАБЛОНЫ
  • AIReiter
  • Блог
  • B2B-разведка по рекламе: почему без HTML-парсера не обойтись и как пережить редизайн

B2B-разведка по рекламе: почему без HTML-парсера не обойтись и как пережить редизайн

Последнее обновление: 2026-07-31 07:04:55

Нужно понять, в каких странах B2B-конкурент размещает рекламу в этом квартале, как долго крутятся креативы, какой у них примерно объём показов и на какие сегменты нацелен таргетинг. Всё это обычно есть в публичной библиотеке рекламы — такие каталоги многие платформы публикуют для соблюдения требований к прозрачности рекламы. Но после открытия DevTools выясняется, что аккуратного JSON-эндпоинта нет: только целая страница серверного HTML. Вы пишете парсер, он работает и отдаёт данные. Через три недели платформа выкатывает редизайн — и парсер без единой ошибки перестаёт извлекать вообще все поля. На выходе тихо появляются пустые значения, на основании которых легко принять неверное решение.

Ниже — о том, как поддерживать такой парсер после редизайнов и где модель реально полезна в его обслуживании. Сначала о границах данных: здесь используются только публичные библиотеки рекламы и creative center самих платформ, доступные при обычном входе под собственным аккаунтом. Никаких подписей, обходов ограничений или непубличных эндпоинтов. Это ограничение прямо заложено в архитектуру парсера.

Почему B2B-рекламу часто приходится извлекать из HTML

Даже библиотеки рекламы отдают данные очень по-разному. Одни потребительские сервисы — например, библиотека рекламы Meta — предлагают структурированный поиск и JSON. Другие требуют активную сессию уже для самого поиска. А библиотеки рекламы большинства B2B-платформ существуют исключительно в виде серверно отрендеренных HTML-страниц, без JSON-эндпоинта. Причина проста: такая библиотека — артефакт compliance, а не продуктовый API.

Её создавали не для разработчиков, а для выполнения требований к прозрачности рекламы. У неё нет версии, changelog и обещаний обратной совместимости. Страница рассчитана на человека: сервер рендерит HTML, и это единственный доступный вам «API».

Хрупкость здесь неизбежна. Вы зависите от деталей чужого интерфейса, владельцы меняют их когда захотят и не обязаны предупреждать. Изменение поля в JSON API хотя бы считается изменением контракта; для команды платформы переделка HTML — обычная фронтенд-итерация. Полностью избежать этого нельзя. Остаётся строить парсер так, чтобы он корректно деградировал и быстро чинился после редизайна, а не молча возвращал пустые поля.

Потоковый парсер снижает не только расход памяти, но и когнитивную нагрузку

Первый импульс — взять lxml или BeautifulSoup, построить DOM всей страницы и пройтись по нему через .find(). Подход рабочий, но для этой задачи он неудачен. DOM — это промежуточное представление, которое браузер создаёт при отрисовке страницы; MDN определяет DOM как дерево узлов, к которому скрипты обращаются через структуру документа. А вам нужно всего лишь достать несколько полей. Полное дерево не требуется — и привязываться к его форме не стоит.

В итоге я остановился на наследнике стандартного Python-класса HTMLParser: чуть больше восьмисот строк, если точно — 881. Это полностью потоковый парсер. Несколько колбэков starttag / data / endtag управляют конечным автоматом: он накапливает данные по мере сканирования, при границе карточки выдаёт запись, очищает состояние и идёт дальше. Полное DOM-дерево никогда не строится.

Выигрыш у потокового подхода вполне практический. Во-первых, память: HTML страницы с деталями легко занимает от десятков до сотен KB, а DOM хранит в памяти структуру всей страницы. Потоковому парсеру достаточно знать лишь текущую точку сканирования и состояние текущей карточки. Но ещё важнее снижение когнитивной нагрузки. Как только вы пишете .find('div').find('div')[2], логика становится зависимой от иерархической позиции в DOM. А именно иерархию редизайн меняет охотнее всего: добавили контейнер, вынесли обёртку — и все позиции сдвинулись. Конечный автомат заставляет спрашивать другое: «То, что я сейчас сканирую, по смыслу является началом карточки, числом показов или тегом таргетинга?» Позиция меняется, семантика — нет.

Три правила, которые помогают пережить редизайн

Всё сводится к трём принципам — каждый из них обычно становится очевиден после очередного редизайна.

Первое: привязывайтесь к смыслу, а не к позиции. Конечный автомат должен переходить по семантическим сигналам: тексту метки поля — читаемым словам вроде «total impressions» или «run dates», маркерам с ролью, семантической границе блока. Но не по логике «третий узел сверху». Проверка очень простая: сохранится ли разбор, если элемент переместят или обернут ещё одним контейнером? Если да — якорь выбран правильно. Позиционные якоря разваливаются при первом же редизайне, семантические обычно выдерживают чисто визуальные изменения.

Второе: отсутствующее поле не должно вызывать исключение. Перед накоплением данных по каждой карточке создавайте объект по шаблону, где все поля имеют пустые значения по умолчанию: пустая строка для текста, None для чисел, пустой массив для списков. Заполняйте то, что нашли, а остальное оставляйте пустым. Сбой при извлечении одного поля не должен уничтожать ни карточку, ни тем более результаты по всей странице. Если у объявления нет текста CTA, всё равно нужны его показы и целевые страны. Терять всю доступную разведывательную ценность страницы из-за второстепенного поля — худшее архитектурное решение.

Третье: отмечайте полноту результата, чтобы «пусто» не выглядело так же, как «сломано». Это самый частый и самый дорогой промах. Ответ «распарсено 0 объявлений» может означать две совершенно разные вещи: у рекламодателя действительно не было рекламы в этом квартале либо структура страницы изменилась и парсер больше ни за что не зацепился. Эти состояния должны различаться в возвращаемом результате. Для этого добавляйте подтверждающие признаки: число найденных карточек, общий объём, заявленный самой страницей, и состояние пагинации. Тогда комбинацию вроде «карточек 0, но метаданные страницы говорят, что должна быть выдача, а маркера следующей страницы нет» можно распознать как структурное изменение и выдать понятную ошибку вместо безразличного пустого списка.

На этом же уровне реализуется упомянутая ранее граница доступа: парсер проверяет, не перебросили ли его на страницу входа. Как только заголовок указывает на login/signup-страницу, он завершает работу с ошибкой, а не пытается её разобрать. Он обрабатывает только публичные страницы, которые вы обычно видите под собственным аккаунтом, останавливается перед login wall и никогда не пытается его преодолеть.

Главная ценность — в срезах и фильтрах, а не в карточке одного объявления

На этом этапе может показаться, что задача — идеально вытащить все поля каждой рекламы. На самом деле нет. Поля одного объявления сами по себе мало что значат; ценность появляется, когда объявления можно разложить по измерениям. Фильтры поиска в библиотеке рекламы уже содержат готовый набор таких измерений. Если представить их в виде программируемых параметров запроса, получится не «одно объявление», а срез запуска конкурента:

  • Страна: где компания рекламируется, а где нет. Если B2B-компания внезапно запускает рекламу в новой стране, это нередко указывает на экспансию раньше, чем её собственный сайт.

  • Период показа — даты начала и окончания: как долго работал конкретный креатив. Долгий срок размещения — сильный сигнал: никто не продолжает платить за креатив, который не конвертирует. Его продолжительность — фактически результат A/B-теста, подтверждённый реальными деньгами и проведённый другой стороной.

  • Диапазон показов — минимум/максимум: грубый индикатор расходов. Абсолютное значение неточно, но его хватает, чтобы расставить приоритеты между размещениями.

  • Аспекты таргетинга: какие настройки включены или исключены. Это наиболее прямой источник данных об аудитории — о тех, кого конкурент считает потенциальными покупателями своего продукта.

Извлечение полей — лишь средство, а эти измерения — цель. Поэтому при проектировании парсера полезно идти от обратного: какие минимальные поля нужно стабильно извлекать, чтобы поддержать запросы и сортировку по этим срезам? Остальные красивые, но второстепенные поля можно не собирать без ущерба для разведки.

После редизайна поручите модели сравнить старый и новый HTML

Парсер такого типа неизбежно сломается после редизайна. И именно при его ремонте модель действительно уместна — но не внутри самого парсинга. Парсинг детерминирован: это жёстко заданный конечный автомат, куда не следует добавлять вызовы модели. Не отдавайте модели детерминированную работу — здесь действует тот же принцип, что и в reverse engineering. Модель нужна для сопровождения.

Рабочий процесс такой: откройте библиотеку рекламы под своим аккаунтом, сохраните HTML до редизайна и HTML после него, передайте оба файла модели вместе со списком полей, которые извлекает текущий парсер. Попросите определить по diff, у каких полей изменились семантические якоря, где теперь должен быть новый якорь и какие несколько строк нужно минимально поправить. Это типичная задача для reasoning-tier: модели нужно найти, сохранилась ли соответствующая семантика в новой структуре, и предложить применимый план, а не ограничиться фразой «структура была изменена». Разным этапам нужны разные способности. Одна модель на всё либо обходится дороже, либо снижает точность:

Этап

Что требуется от модели

Выбор

model id

Прочитать всю SSR HTML-страницу и сопоставить старую и новую структуру

Длинный контекст: модель должна целиком принять страницу с деталями размером от десятков до сотен KB

Kimi K3

kimi-k3

После редизайна разобрать diff старого и нового HTML, определить дрейф якоря и предложить минимальную правку

Сильное рассуждение: объясняет изменение через структуру, а не просто повторяет факт

Claude Opus 5

claude-opus-5

Массово нормализовать и размечать карточки сотен рекламодателей в разведывательные данные

Низкая стоимость, сотни или тысячи вызовов с высокой параллельностью

Claude Sonnet 5

claude-sonnet-5

Установить причину расхождения, когда сравнение с фикстурой не проходит

Средний уровень рассуждений: объяснение через «ожидаемое поле против фактического извлечения»

GPT-5.6 Sol

gpt-5.6-sol

Второй уровень — ключевой и единственный этап, где смена модели заметно влияет на результат. Не верьте на слово, что здесь нужен reasoning-tier: это легко проверить коротким протоколом.

  1. Сохраните HTML одной страницы до редизайна и после него: откройте библиотеку рекламы под своим аккаунтом и сохраните страницу.

  2. Передайте оба HTML-файла вместе со списком полей текущего парсера в claude-opus-5 и gpt-5.6-sol.

  3. Оцените один критерий: указывает ли предложенное исправление на конкретную смену семантического якоря — например, «раньше якорем была метка 'total impressions', в новой версии изменилась роль контейнера этой метки, переключите якорь на X» — или ограничивается расплывчатым «структура была изменена, рекомендуем адаптировать решение».

  4. Первый ответ можно применить сразу, второй ничего не даёт. В этом и состоит критерий выбора: от него напрямую зависит, сколько итераций вслепую вы пройдёте в день редизайна.

Одного такого сравнения достаточно, чтобы увидеть разницу яснее любого бенчмарка.

Главная проблема — цена переключения между моделями

Четыре уровня распределены между тремя вендорами, тремя SDK, тремя схемами авторизации и тремя форматами ошибок. Большинство смотрит на объём работы по подключению трёх клиентов для разных этапов, решает, что это не стоит усилий ради «редкого ремонта парсера и массовой очистки данных», и остаётся на одной модели. В итоге для починки после редизайна используется уровень, который умеет лишь сказать «рекомендуем адаптировать», — время тратится, а причина неясна.

AIReiter убирает этот слой сложности: один ключ, один OpenAI-совместимый интерфейс, все четыре уровня за ним. Для переключения достаточно изменить поле model в теле запроса.

# Исправление после редизайна: reasoning-tier
curl https://aireiter.com/api/v1/chat/completions \
  -H "Authorization: Bearer $AIREITER_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-opus-5",
    "messages": [{"role": "user", "content": "<old-new HTML diff + current field list, ask where the anchor drifted>"}]
  }'

# Массовая нормализация разведданных: меняем model, остальное оставляем как есть
#   "model": "claude-sonnet-5"
# Длинный контекст для чтения всей страницы: "model": "kimi-k3"
# Установление причины расхождений:          "model": "gpt-5.6-sol"

Если вы уже используете OpenAI SDK, укажите для base_url значение https://aireiter.com/api/v1 и больше ничего не меняйте. Для Anthropic SDK используйте POST /api/v1/messages с тем же ключом.

По цене: модели Claude доступны со скидкой 30% от прайс-листа, модели GPT — за половину цены, а Kimi K3 вызывается тем же ключом. В этом сценарии скидка приходится на основные расходы. Главная статья — не ремонт после редизайна: это редкий, но ценный вызов. Основные затраты создаёт массовая нормализация разведывательных данных: вы отслеживаете двадцать рекламодателей-конкурентов, у каждого десятки или сотни карточек, и передаёте их модели, чтобы выделить обещание, аудиторию и период показа. Это самый плотный по вызовам этап, выполняемый на Claude Sonnet со скидкой 30%. Следом идёт длинный контекст для чтения целой страницы и сопоставления структуры. Две самые дорогие части процесса как раз покрываются скидкой.

  • Получить API-ключ

  • Попробовать без регистрации: вручную передайте одной и другой модели пару HTML до и после изменений, сравните, какая действительно укажет место дрейфа якоря, и уже затем решайте, стоит ли подключать это в процесс.

После ремонта парсера и массовой нормализации исходных карточек следующий шаг — передать эту разведку в creative pipeline для принятия решений и генерации ассетов. Этому посвящён полный цикл от ключевого слова до готового объявления; текущая статья описывает его самый ранний этап — надёжное извлечение публичных данных.

Последнее слово о корректности полей остаётся за фикстурой

Пока исправление от модели не прошло проверку, это лишь рекомендация. Модель может сказать: «якорь нужно заменить на X», и предложение будет выглядеть логично, но нет гарантии, что X подходит для всех карточек. B2B-объявления бывают с изображением и текстом, только текстовые, карусельные, с посадочной страницей и без неё. Два примера, которые видела модель, могут не покрывать всё разнообразие.

Защита здесь та же, что и от галлюцинаций модели в reverse engineering: сравнение по фиксированному вектору. Сохраните набор известных входов — несколько HTML реальных страниц — и их заведомо корректные выходы, то есть результаты извлечения полей, однажды проверенные вручную. Оформите их как фикстуру и закоммитьте в репозиторий. При каждом изменении парсера, сделанном вручную или по рекомендации модели, запускайте этот набор заново и сравнивайте поля по одному. Только так после внешнего редизайна можно быстро понять: «я неправильно применил рекомендацию или страница снова изменилась?» Если всё проходит — правка верна. Если падают отдельные случаи, проблемные поля в них сразу показывают, на каком слое находится ошибка. Модель генерирует предложения по ремонту, фикстура определяет, верны ли они; смешивать эти роли нельзя. Полный метод такого дифференциального сравнения описан в материале о дифференциальном тестировании; к парсеру библиотеки рекламы применяется тот же барьер. Без него вы принимаете уверенность модели за корректность. Тогда легко «внести правку, не увидеть ошибок, выкатить её — и через три дня обнаружить, что данные по одной стране всё это время были пустыми».

Итог

B2B-разведку по рекламе часто приходится извлекать из HTML, потому что библиотека рекламы — это compliance-артефакт, а не продуктовый API: у неё нет контракта, а редизайн может случиться в любой момент. Устойчивость к изменениям держится на трёх принципах: использовать семантические, а не позиционные якоря; корректно переживать отсутствие полей вместо исключений; отмечать полноту результата, чтобы «пусто» и «сломано» не смешивались. Настоящая ценность не в полях отдельного объявления, а в измерениях, по которым можно разложить запуск конкурента: стране, периоду показа, диапазону показов и аспектам таргетинга. У модели здесь конкретная роль: не парсинг, который должен оставаться детерминированным конечным автоматом, а сопровождение. После редизайна reasoning-tier помогает сопоставить старую и новую структуру и предложить ремонт, а недорогой уровень с высокой параллельностью подходит для массового превращения карточек в разведывательные данные. Но окончательное решение о корректности полей всегда принимает фикстура. Подключите эти уровни через единый интерфейс — и единственным трением останется смена поля model, которую решает выбор модели.

>_Каталог моделей AIReiter

Быстрый API-доступ к моделям, связанным с этим гайдом

Claude Opus 5

Chat

Премиальная модель Claude для сложного анализа, программирования и профессиональной работы с длинным контекстом.

anthropicСоздать API Key >

Claude Sonnet 5

Chat

Сбалансированная модель Claude для продвинутого рассуждения, программирования и повседневной работы.

AnthropicСоздать API Key >

Kimi K3

Chat

Модель для рассуждений с длинным контекстом для программирования, письма, анализа и агентных рабочих процессов.

moonshotСоздать API Key >

GPT-5.6 Sol

Chat

Премиальная текстовая модель GPT-5.6 для требовательного программирования, рассуждений и длительной агентной работы.

OpenAIСоздать API Key >

Claude Fable 5

Chat

Премиальная модель Claude для глубокого рассуждения и сложной объемной работы.

AnthropicСоздать API Key >

Недавние статьи

Снижение цен на GPT-5.6: сколько теперь стоят Luna и Terra

2026-07-31

Invalid API Key: как разобраться с 401 и 403 до замены ключа

2026-07-31

Как исправить ошибку OpenRouter 429: лимит платформы или провайдера?

2026-07-31

DeepSeek V4 Flash vs GLM-5.2: тест после обновления 0731

2026-07-31
AIREITER

Есть вопросы? Свяжитесь с нами
[email protected]

LLM

Gemini 3.6 FlashGemini 3.1 ProKimi K3Gemini 3 ProGemini 2.5 Pro

AI-видео

Kling 3.0 Motion ControlSora 2 ProKling 3.0 TurboSora 2Kling 3.0

AI-изображения

FLUX.2 ProGPT-Image 2Wan 2.7 Image ProGPT 4o ImageSeedream 5.0 Pro

Блог

Посмотреть все →

Компания

Политика конфиденциальностиУсловия обслуживанияПолитика возврата

© 2026 AIReiter. Все права защищены.