Разбор

ИИ-агент анализирует конкурентов в Яндексе: кто в топе, почему они там и что с этим делать

7 из 15 ключей вышли в ТОП-5 за 2 месяца после внедрения рекомендаций ИИ-агента. Python + Яндекс Search API + Claude анализируют ТОП-10 конкурентов за 20 минут вместо 2–3 дней ручной работы.

• 8 мин чтения

2–3 дня на анализ конкурентов в выдаче — и делается это раз в квартал, если вообще делается. За три месяца конкуренты успевают переписать страницы, добавить новые разделы и уйти в ТОП, пока ты смотришь на позиции и гадаешь почему они не растут.

20 мин
вместо 2–3 дней — столько занимает полный анализ ТОП-10 конкурентов по 15 ключам с помощью ИИ-агента

Почему ручной анализ не работает как система

Вот как обычно устроен процесс. Раз в квартал (в лучшем случае) SEO-специалист или маркетолог открывает Яндекс, вбивает один из целевых запросов, заходит на каждый из ТОП-10 сайтов, смотрит на структуру страницы, копирует title и H1 в таблицу. По одному запросу это 30–45 минут. По пятнадцати — два-три дня.

При этом сам процесс субъективный. Один человек обратит внимание на структуру заголовков, другой — на длину текста, третий — на LSI-слова. Систематического сравнения не получается. А рекомендации — «добавить ключевое слово в title» — слишком общие, чтобы от них был толк.

Три вещи, которые мешают делать это часто и хорошо:

Время. Два дня работы ради выводов, которые устаревают раньше чем успеваешь их внедрить — плохая сделка. Поисковая выдача меняется быстро, особенно в коммерческих нишах.

Структура. Таблица с конкурентами, куда вручную вбиты title и H1 — это данные, а не инсайты. Из сырых данных нужно ещё извлечь паттерны: что общего у ТОП-3, чего нет у тебя, что можно добавить. На это уходит ещё день.

Частота. Когда процесс занимает три дня, его делают раз в квартал. Когда это 20 минут — каждую неделю. Разница в подходе к SEO принципиальная.

Что анализирует агент

Агент собирает по каждому конкуренту из ТОП-10 шесть типов данных:

ЭлементЧто именно берёмЗачем
TitleПолный текст, длина в символахПаттерны заголовков в ТОП
H1Текст первого заголовкаКак формулирует тему лидер
DescriptionМета-описаниеКонкурентные триггеры в сниппете
Структура текстаВсе H2 и H3, их количествоГлубина охвата темы
LSI-словаТоп-30 n-грамм из текста страницыСемантическое окружение
Ссылки в текстеВнутренние ссылки из контентаПерелинковка и тематические кластеры

Дальше начинается сравнение. Claude получает эти шесть блоков по каждому из ТОП-10 плюс те же данные с твоей страницы — и сравнивает их структурно. На выходе конкретная рекомендация: какой раздел добавить, как переписать H1, каких тематических блоков не хватает для выхода в ТОП.

Схема работы агента

🔍Яндекс Search APIТОП-10 URL по запросу
🕸️BeautifulSoupпарсинг HTML страниц
📋JSON-срезструктурированные данные
🤖Claude Sonnetанализ и рекомендации
📄Отчётконкретные правки

Python — оркестратор. Сам он ни с чем не взаимодействует напрямую, только забирает данные и передаёт дальше. Яндекс Search API отдаёт URL-ы из выдачи по запросу, BeautifulSoup разбирает HTML каждого сайта, Claude получает структурированный JSON и формирует рекомендации.

Важный момент с архитектурой: я не делал Claude «агентом с инструментами», который сам решает что парсить. Для регулярного мониторинга это лишняя сложность. Фиксированная схема сбора данных → одна передача в Claude → отчёт. Так дешевле и предсказуемее.

Код

🐍 competitor_analysis.py — pip install anthropic httpx beautifulsoup4 lxml
import httpx
import anthropic
import json
import re
from collections import Counter
from bs4 import BeautifulSoup

YANDEX_SEARCH_API_KEY = "YOUR_API_KEY"     # Yandex Cloud IAM-токен
YANDEX_FOLDER_ID = "YOUR_FOLDER_ID"        # Folder ID в Yandex Cloud
CLAUDE_API_KEY = "YOUR_CLAUDE_KEY"         # Anthropic API key

SEARCH_API_URL = "https://searchapi.api.cloud.yandex.net/v2/web/search"

HEADERS_HTML = {
  "User-Agent": "Mozilla/5.0 (compatible; SEO-Analyzer/1.0)",
  "Accept": "text/html,application/xhtml+xml",
  "Accept-Language": "ru-RU,ru;q=0.9",
}


def get_top10_urls(query: str) -> list[str]:
  """Получаем ТОП-10 URL из Яндекса по запросу."""
  payload = {
      "query": {"searchType": "SEARCH_TYPE_RU", "queryText": query},
      "sortSpec": {"sortType": "SORT_TYPE_BY_RELEVANCE"},
      "groupSpec": {"groupMode": "GROUP_MODE_FLAT", "groupsOnPage": 10},
      "folderId": YANDEX_FOLDER_ID,
  }
  headers = {
      "Authorization": f"Api-Key {YANDEX_SEARCH_API_KEY}",
      "Content-Type": "application/json",
  }
  with httpx.Client(timeout=30) as client:
      r = client.post(SEARCH_API_URL, json=payload, headers=headers)
      r.raise_for_status()
      data = r.json()

  urls = []
  for group in data.get("response", {}).get("grouping", []):
      for doc in group.get("group", []):
          for d in doc.get("document", []):
              url = d.get("url", "")
              if url and url not in urls:
                  urls.append(url)
  return urls[:10]


def extract_ngrams(text: str, n: int = 2) -> list[str]:
  """Топ-30 биграмм из текста."""
  words = re.findall(r'[а-яёa-z]{3,}', text.lower())
  ngrams = [' '.join(words[i:i+n]) for i in range(len(words)-n+1)]
  counter = Counter(ngrams)
  return [ng for ng, _ in counter.most_common(30)]


def parse_page(url: str) -> dict:
  """Парсим страницу: title, h1, description, h2/h3, LSI, ссылки."""
  try:
      with httpx.Client(timeout=15, follow_redirects=True, headers=HEADERS_HTML) as client:
          r = client.get(url)
          r.raise_for_status()
          soup = BeautifulSoup(r.text, 'lxml')

      title = soup.title.get_text(strip=True) if soup.title else ''
      h1_tag = soup.find('h1')
      h1 = h1_tag.get_text(strip=True) if h1_tag else ''
      meta_desc = ''
      meta = soup.find('meta', attrs={'name': 'description'})
      if meta:
          meta_desc = meta.get('content', '')

      h2s = [t.get_text(strip=True) for t in soup.find_all('h2')]
      h3s = [t.get_text(strip=True) for t in soup.find_all('h3')]

      # Основной текст без навигации и футера
      for tag in soup(['nav', 'footer', 'header', 'script', 'style']):
          tag.decompose()
      body_text = soup.get_text(' ', strip=True)

      lsi = extract_ngrams(body_text)

      # Внутренние ссылки из контента
      base_domain = url.split('/')[2] if '/' in url else ''
      links = []
      for a in soup.find_all('a', href=True):
          href = a['href']
          if base_domain in href or href.startswith('/'):
              text = a.get_text(strip=True)
              if text and len(text) > 3:
                  links.append(text)

      return {
          'url': url,
          'title': title[:120],
          'h1': h1[:120],
          'description': meta_desc[:200],
          'h2_list': h2s[:15],
          'h3_count': len(h3s),
          'lsi_bigrams': lsi[:20],
          'internal_links': list(set(links))[:15],
          'error': None,
      }
  except Exception as e:
      return {'url': url, 'error': str(e), 'title': '', 'h1': ''}


def analyze_with_claude(query: str, my_page: dict, competitors: list[dict]) -> str:
  """Claude сравнивает твою страницу с конкурентами и даёт рекомендации."""
  client = anthropic.Anthropic(api_key=CLAUDE_API_KEY)

  # Берём только успешно спарсенных конкурентов
  ok_comps = [c for c in competitors if not c.get('error')]

  prompt = f"""Ты SEO-аналитик. Запрос: "{query}"

МОЯ СТРАНИЦА:
{json.dumps(my_page, ensure_ascii=False, indent=2)}

КОНКУРЕНТЫ В ТОП-{len(ok_comps)} (отсортированы по позиции):
{json.dumps(ok_comps, ensure_ascii=False, indent=2)}

Задача: выяви конкретные причины, почему конкуренты выше, и дай практические рекомендации.

Структура ответа:
1. ГЛАВНЫЙ РАЗРЫВ (1–2 предложения: в чём принципиальное отличие ТОП-1 от моей страницы)
2. ЧТО ДОБАВИТЬ В TITLE И H1 (конкретные формулировки с примерами)
3. СТРУКТУРА ТЕКСТА (каких разделов не хватает — с названиями H2)
4. LSI-СЛОВА КОТОРЫХ НЕТ У МЕНЯ (список 10–15 слов/фраз из конкурентов)
5. ТРИ ДЕЙСТВИЯ НА ЭТОЙ НЕДЕЛЕ (конкретные, с критерием «что считать выполненным»)

Пиши по-русски, конкретно, без воды."""

  message = client.messages.create(
      model="claude-sonnet-4-6",
      max_tokens=1500,
      messages=[{"role": "user", "content": prompt}]
  )
  return message.content[0].text


def run_analysis(query: str, my_url: str) -> str:
  """Полный цикл: получить конкурентов → спарсить → проанализировать."""
  print(f"Запрос: {query}")

  top10 = get_top10_urls(query)
  # Убираем свой сайт из списка конкурентов
  competitors_urls = [u for u in top10 if my_url not in u]
  print(f"Найдено конкурентов: {len(competitors_urls)}")

  my_page = parse_page(my_url)
  print(f"Своя страница: {my_page.get('title', 'н/д')}")

  competitors = []
  for i, url in enumerate(competitors_urls[:10], 1):
      print(f"  Парсим {i}/{len(competitors_urls)}: {url[:60]}...")
      competitors.append(parse_page(url))

  report = analyze_with_claude(query, my_page, competitors)
  return report


# Пример запуска для одного ключа
if __name__ == "__main__":
  QUERY = "купить ламинат недорого москва"
  MY_URL = "https://example.com/catalog/laminat/"

  result = run_analysis(QUERY, MY_URL)
  print("\n" + "="*60)
  print(result)

Несколько вещей, которые в документации не очевидны.

Яндекс Search API на Yandex Cloud предоставляет два метода: /web/search (синхронный, ответ сразу) и /web/searchAsync (асинхронный, возвращает ID операции — нужно поллить /operations/{id}). Скрипт использует синхронный вариант: проще для старта, ответ получаем в том же запросе. Для потоков из 50+ запросов параллельно стоит перейти на async-версию.

robots.txt конкурентов стоит проверять отдельно. BeautifulSoup не нарушает никаких ограничений — парсинг HTML это то, что делает любой браузер. Но часть сайтов блокирует автоматические запросы через User-Agent или rate limit. Скрипт обрабатывает ошибки через try/except — упавшие URL просто пропускаются.

Микрокавычки в f-строках Python внутри MDX могут вызвать проблемы при рендеринге — именно поэтому в промпте использованы одинарные кавычки вместо тройных.

Пример отчёта Claude

Вот реальный фрагмент отчёта по запросу «ламинат 33 класс купить москва» для магазина строительных материалов:

🤖 Отчёт Claude — запрос «ламинат 33 класс купить москва» — позиция моей страницы до правок: 23
1. ГЛАВНЫЙ РАЗРЫВ ТОП-1 (laminate.ru) имеет отдельный раздел "Почему 33 класс" с объяснением разницы классов — у вас этого нет вообще. Яндекс считает их страницу более релевантной по информационной составляющей, хотя коммерческий запрос. 2. ЧТО ДОБАВИТЬ В TITLE И H1 Сейчас у вас: "Ламинат 33 класс — каталог | StroyMag" ТОП-1: "Ламинат 33 класс — купить от 890 ₽/м² | Доставка 1 день | laminate.ru" ТОП-2: "Ламинат 33 класс | 247 товаров с ценами и фото | stroydom.ru" Добавьте в title: цену от, количество товаров, срок доставки. H1 измените на: "Ламинат 33 класс — {кол-во} товаров от {цена} ₽/м²" 3. СТРУКТУРА ТЕКСТА (каких разделов не хватает) У конкурентов ТОП-1...3 есть следующие H2, которых нет у вас: — "Чем отличается 33 класс от 32 и 34" — "Как выбрать ламинат 33 класса: пошаговый гайд" — "Ламинат 33 класса для разных помещений" (с таблицей) — "Вопросы и ответы" (FAQ-блок, 6–8 вопросов) 4. LSI-СЛОВА КОТОРЫХ НЕТ У МЕНЯ влагостойкий, толщина 8мм, подложка, укладка, износостойкость, AC5, HDF-плита, замковое соединение, гарантия, сертификат, норма нагрузки, помещение с высокой проходимостью, натуральный декор, антистатическое покрытие, европейское производство 5. ТРИ ДЕЙСТВИЯ НА ЭТОЙ НЕДЕЛЕ → Переписать title: добавить "от X ₽/м²" и "N товаров". Критерий: title изменён, индексация обновится за 3–7 дней. → Добавить раздел "Чем отличается 33 класс": 300–400 слов, таблица сравнения классов. Критерий: раздел опубликован, в H2 есть слово "отличается". → Добавить FAQ-блок: 6 вопросов из подсказок Яндекса по запросу. Критерий: FAQ размечен schema.org, 6+ пар Q&A.

Обратите внимание на структуру: не «добавьте ключевые слова», а конкретные формулировки с примерами того, как это сделали конкуренты. Критерии выполнения — чтобы не гадать «ну мы вроде добавили».

Ограничения Яндекс Search API

Яндекс в 2024 году перенёс XML API на Yandex Cloud. Старый xml.yandex.ru продолжает работать для аккаунтов с историческим доступом, но новые подключения — только через Yandex Cloud Search API.

Модель доступа: платная подписка с лимитами на количество запросов, привязанная к Folder ID в Yandex Cloud. Бесплатного постоянного уровня нет — есть тестовый период. Актуальные тарифы: cloud.yandex.ru/services/search-api.

Для еженедельного мониторинга 15 ключей расход небольшой: один прогон — 15 запросов к Search API, это около 150 запросов в месяц при запуске раз в неделю. На большинстве тарифных планов это укладывается в минимальный пакет.

Одно практическое ограничение, с которым я столкнулся: API возвращает данные только по поиску в России (searchType: SEARCH_TYPE_RU). Региональная выдача (например, ТОП по Казани) требует отдельного параметра геотаргетинга — lr (номер региона в базе Яндекса).

Как проверить состояние своего SEO прямо сейчас

Диагностика: насколько вы знаете своих конкурентов

4 вопроса — поймёте, где пробел

Вопрос 1 из 4
Когда последний раз смотрели, что именно написано в title и H1 у ТОП-1 по вашим главным запросам?
Вопрос 2 из 4
Знаете ли вы, каких разделов (H2) нет на ваших страницах, но есть у конкурентов из ТОП-3?
Вопрос 3 из 4
Как часто обновляете контент страниц на основе изменений в выдаче конкурентов?
Вопрос 4 из 4
Есть ли у вас список LSI-слов которые используют конкуренты, но которых нет на ваших страницах?

Кейс: 15 ключей, 2 месяца, 7 позиций в ТОП-5

Интернет-магазин строительных материалов, Москва и МО. 15 коммерческих ключей в нише напольных покрытий. До запуска агента позиции стояли на одном месте восемь месяцев — между 15-й и 35-й строкой выдачи, без существенного движения.

Хронология внедрения
Нед. 1
Первый запуск агента по всем 15 ключам. Отчёт: 11 страниц с конкретными правками. Приоритет — title, H1 и добавление FAQ-блоков на 7 страницах.
Нед. 2–3
Внедрили рекомендации: переписали title/H1 на 9 страницах, добавили FAQ-разделы, дополнили тексты LSI-словами из отчёта.
9 стр.
Нед. 4
Повторный запуск агента. Обнаружил: два конкурента обновили страницы и снова вырвались вперёд. Новые рекомендации по структуре текста и внутренней перелинковке.
+2 итерации
Мес. 2
Результат замера: 7 ключей в ТОП-5, ещё 4 в ТОП-10. Оставшиеся 4 ключа — высококонкурентные, там нужны ссылки, не только контент.
7/15 в ТОП-5

Что сработало, а что нет.

Быстрее всего поднялись ключи, где разрыв был в структуре: у конкурентов были FAQ-блоки и сравнительные таблицы, у нас — просто текст. Добавили — позиции подросли за 2–3 недели.

Медленнее — ключи с высокой конкуренцией, где у ТОП-3 ещё и ссылочная масса в разы больше. Контентные правки помогли, но не дотянули до первой страницы.

Четыре ключа так и остались на 12–18 позиции. Агент честно написал в отчёте: «Контентный разрыв минимален, разница в ссылочном профиле — основной фактор».

Это, кстати, честный ответ. Агент не обещает ТОП по любому запросу — он показывает конкретно где разрыв и что можно сделать.

Как настроить еженедельный мониторинг

1
Зарегистрироваться в Yandex Cloud и подключить Search API

Создать аккаунт на cloud.yandex.ru, создать каталог (Folder), подключить сервис Search API. Получить API-ключ или IAM-токен. Проверить актуальный тариф на странице услуги.

cloud.yandex.ru → Каталог → Search API → Включить
2
Установить зависимости Python

Четыре библиотеки: anthropic для Claude API, httpx для асинхронных HTTP-запросов, beautifulsoup4 и lxml для парсинга HTML. Python 3.10+.

pip install anthropic httpx beautifulsoup4 lxml
3
Подготовить список ключей и URL своих страниц

Сделать JSON-файл: список пар {query: "запрос", my_url: "https://..."} для каждого целевого ключа. Начинать с 5–10 ключей — меньше расход API и проще проверить качество отчётов.

4
Запустить вручную и проверить качество отчёта

Прогнать скрипт по 2–3 ключам, посмотреть на рекомендации. Если Claude пишет слишком общо — значит парсинг вернул пустые страницы (часто из-за JavaScript-рендеринга). В таком случае нужен Playwright или Splash вместо httpx.

python competitor_analysis.py
5
Настроить запуск по расписанию

Cron каждый понедельник в 9:00 — скрипт прогоняет все ключи из списка, сохраняет отчёты в папку с датой. Можно добавить отправку в Telegram или на email через тот же скрипт.

0 9 * * 1 python /path/to/competitor_analysis.py

Где агент не поможет

Честно о границах — потому что ожидания управляют результатом.

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

Агент не видит ссылочный профиль. Если ТОП-1 держится на 500 качественных ссылках, а у тебя 20 — контентные правки поднимут позиции, но не до первого места. Агент иногда пишет об этом явно, но не всегда.

Агент не работает с JavaScript-рендеренными страницами. Если конкурент использует SPA на React или Vue, BeautifulSoup увидит пустую болванку вместо контента. Для таких случаев нужен headless-браузер (Playwright, Puppeteer) — это отдельная тема.

Агент не анализирует поведенческие факторы. Почему ТОП-1 держится несмотря на слабый контент — может быть высокий CTR в сниппете, долгое время на сайте, прямые заходы. Это не видно из HTML.

Но вот что я заметил после нескольких месяцев использования: большинство SEO-задач решаются именно на уровне контента и структуры. Ссылочная конкуренция — в коммерции и в узких нишах. В большинстве тематик разрыв между твоей страницей и ТОП-3 — это три H2, которых ты не написал, и пятнадцать слов, которых нет в тексте.

Источники

Источники

Часто задаваемые вопросы

Что такое Яндекс Search API и зачем он нужен для анализа конкурентов?
Яндекс Search API (бывший Яндекс XML) — программный интерфейс для получения результатов поиска Яндекса без браузера. Скрипт делает запрос с ключевой фразой и получает ТОП-10 URL в XML. Дальше каждый URL можно автоматически обойти и разобрать: заголовки, мета-теги, структуру текста, LSI-слова. Это заменяет ручной просмотр выдачи и копирование данных в таблицу.
Сколько времени экономит ИИ-агент по сравнению с ручным анализом конкурентов?
Ручной анализ ТОП-10 по одному запросу — 30–45 минут: зайти на каждый сайт, переписать H1, title, description, посмотреть структуру текста, найти LSI-слова. По 15 ключам это 2–3 рабочих дня. Агент делает то же самое за 20–30 минут, включая формирование отчёта Claude с конкретными рекомендациями.
Какие ограничения есть у Яндекс Search API?
Яндекс Search API (Yandex Cloud) работает по подписке, лимиты на запросы устанавливаются на уровне аккаунта в Yandex Cloud. Бесплатного постоянного доступа нет — есть тестовый период. Для еженедельного мониторинга 15–30 ключей расход небольшой: обычно укладывается в несколько сотен запросов в месяц. Проверить актуальные тарифы: cloud.yandex.ru/services/search-api.
Что именно Claude анализирует в сниппетах конкурентов?
Claude получает структурированный JSON: H1, title, description, первый абзац текста, количество заголовков H2/H3, список ссылок со страницы, частотные n-граммы из текста. Модель сравнивает это с твоей страницей и выдаёт конкретные рекомендации: каких слов не хватает, какую структуру добавить, где конкурент явно лучше и почему.
Нужно ли уметь программировать, чтобы запустить агента?
Достаточно базового Python: установить библиотеки, вставить API-ключи, запустить скрипт. Всё остальное делает код из статьи. Для автоматического еженедельного запуска понадобится cron (Linux) или любой планировщик задач. Более сложная часть — зарегистрироваться в Yandex Cloud и пройти верификацию для доступа к Search API.
Какой реальный результат дало внедрение рекомендаций агента?
Кейс из статьи: интернет-магазин строительных материалов, 15 коммерческих ключей. После двух итераций доработки страниц по рекомендациям ИИ-агента — 7 ключей вышли в ТОП-5, ещё 4 в ТОП-10. Срок — 2 месяца с момента первого запуска агента. До этого позиции стояли на месте 8 месяцев.
Обсуждение

    Пока без комментариев. Будьте первым.

    Войдите, чтобы отправить комментарий

    Вы сможете комментировать статьи, сохранять материалы

    или войдите по email

    Бесплатная диагностика · 30 минут · без обязательств

    Маркетинг работает, но продажи не растут?

    Отвечу на 3–5 вопросов о вашем бизнесе — и мы вместе разберём, где именно теряются клиенты и что с этим делать.

    Без продаж. Без навязчивых звонков.