# Как разобрать маркетинговую воронку конкурента по ссылке с помощью ИИ: реклама, соцсети, SEO

> AI Release · @ai_release1 · https://ai-release.org/guides/kak-razobrat-marketingovuyu-voronku-konkurenta-po-ssylk.html

## TL;DR
- Время выполнения: 60–90 минут на один домен
- Уровень сложности: Intermediate
- Понадобится: Python 3.x (только стандартная библиотека), curl, ключ доступа к LLM API (OpenAI-совместимый эндпоинт; конкретную модель и лимиты сверьте с документацией провайдера), ~200 МБ на диске, таблица (Google Sheets или Excel) для сводки

## Требования и подготовка
![Иллюстрация к разделу «Требования и подготовка»](https://ai-release.org/guides/img/kak-razobrat-marketingovuyu-voronku-konkurenta-po-ssylk-ru-1.jpg)


- ОС: Linux, macOS или WSL; на Windows — PowerShell либо WSL (версию проверьте командой `$PSVersionTable`).
- Права: запись в рабочую папку, исходящие HTTPS-запросы на порт 443.
- Пакеты: ничего устанавливать не нужно, все скрипты ниже работают на стандартной библиотеке Python (`urllib`, `json`, `re`, `pathlib`). Если хотите `requests`/`bs4` — сверьтесь с документацией по установке.
- Переменные окружения: `LLM_BASE_URL`, `LLM_MODEL`, `LLM_API_KEY`.
- Юридическая рамка: собираем только публичные страницы, соблюдаем `robots.txt` и условия использования сайта (ToS — terms of service, правила площадки), не сохраняем персональные данные (имена, телефоны, e-mail из форм).

**Что сделать:** проверить инструменты и задать переменные окружения.

**Зачем:** если ключ или `curl` недоступны, все последующие шаги упадут на середине и результат будет неполным.

**Как проверить:** каждая команда должна вернуть версию или подтверждение.

```bash
python3 --version
curl --version | head -n 1
df -h . | tail -n 1

export LLM_BASE_URL="https://<ваш-llm-эндпоинт>"
export LLM_MODEL="<модель-из-документации>"
export LLM_API_KEY="<ключ>"
test -n "$LLM_API_KEY" && echo "key set"
```

Ожидаемый вывод: строка вида `Python 3.x.x`, `curl 8.x.x`, строка с свободным местом и `key set`.

**Пример:** `df -h . | tail -n 1` печатает `/dev/sda1  100G  20G  80G  20% /` — 80 ГБ свободно, места достаточно.

**Что сделать:** прочитать `robots.txt` проверяемого домена.

**Зачем:** файл `robots.txt` — текстовый список правил для роботов; если там `Disallow: /`, автоматический сбор запрещён и дальше идти нельзя.

```bash
curl -sS "https://<ваш-домен>/robots.txt" | head -n 20
```

Ожидаемый вывод: строки `User-agent: *`, `Disallow: ...` и, часто, `Sitemap: https://<ваш-домен>/sitemap.xml`. Запомните путь к sitemap — он понадобится на шаге 1.

## Шаг 1. Собрать публичную базу: лендинг, robots.txt, sitemap, рекламные метки

**Что сделать:** создать рабочую папку и скачать три публичных файла.

**Зачем:** это исходники, по которым ИИ будет строить карту воронки (воронка — путь от первого касания с рекламой до покупки). Без локальных копий нечего проверять: любая фраза модели останется без доказательства.

```bash
mkdir -p funnel/<ваш-домен>/{raw,out}
curl -sSL -A "Mozilla/5.0 (compatible; FunnelAudit/1.0)" \
  "https://<ваш-домен>/" -o funnel/<ваш-домен>/raw/index.html
curl -sSL "https://<ваш-домен>/robots.txt" -o funnel/<ваш-домен>/raw/robots.txt
curl -sSL "https://<ваш-домен>/sitemap.xml" -o funnel/<ваш-домен>/raw/sitemap.xml
```

Флаг `-L` заставляет curl идти по редиректам (частая причина «пустого» файла), `-A` подставляет честный User-Agent — строку, которой клиент представляется серверу.

**Как проверить:**

```bash
wc -c funnel/<ваш-домен>/raw/index.html
grep -c "<loc>" funnel/<ваш-домен>/raw/sitemap.xml
```

Ожидаемый вывод: число больше `10000` для `index.html` и число больше `1` для sitemap. Если `index.html` весит 0 байт — см. раздел проблем.

**Что сделать:** вытащить из HTML заголовки, описание, H1, кнопки-призывы (CTA — call to action, текст кнопки «Купить», «Оставить заявку») и список счётчиков аналитики.

**Зачем:** заголовок и H1 показывают оффер (обещание клиенту), CTA — этап воронки, а счётчики (`gtag`, `fbq`, `ym`) — на каких рекламных платформах конкурент вообще ведёт кампании.

```python
# funnel/<ваш-домен>/extract.py
import sys, json, re
from pathlib import Path

html = Path(sys.argv[1]).read_text(encoding="utf-8", errors="ignore")

def first(pattern):
    m = re.search(pattern, html, re.I | re.S)
    return re.sub(r"\s+", " ", m.group(1)).strip() if m else None

data = {
    "title": first(r"<title[^>]*>(.*?)</title>"),
    "description": first(r'<meta[^>]+name=["\']description["\'][^>]+content="\'["\']'),
    "h1": first(r"<h1[^>]*>(.*?)</h1>"),
    "counters": sorted(set(re.findall(r"\b(gtag|fbq|ym|rtrg)\b", html))),
    "cta": re.findall(r"<a[^>]+>([^<]{3,60})</a>", html)[:20],
}
Path("out/page.json").write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
print("OK:", len(data["cta"]), "CTA, счётчики:", data["counters"])
```

**Пример:** запуск `python3 extract.py funnel/example.com/raw/index.html` печатает `OK: 14 CTA, счётчики: ['fbq', 'gtag', 'ym']` — значит, на странице стоят пиксели трёх рекламных систем.

**Как проверить:** откройте `funnel/<ваш-домен>/out/page.json` — поля `title` и `h1` не должны быть `null`. Если `null`, значит разметка страницы нестандартная: сверьтесь с HTML вручную через `grep -i "<title" raw/index.html`.

## Шаг 2. Прогнать данные через ИИ и получить карту воронки в жёсткой схеме
![Иллюстрация к разделу «Шаг 2. Прогнать данные через ИИ и получить карту воронки в жёсткой схеме»](https://ai-release.org/guides/img/kak-razobrat-marketingovuyu-voronku-konkurenta-po-ssylk-ru-2.jpg)


**Что сделать:** сохранить промпт-инструкцию в файл `prompt.txt` рядом со скриптом.

**Зачем:** без схемы модель отвечает свободным текстом, и результат нельзя ни сравнить между доменами, ни проверить. Требование поля `evidence` (доказательство) заставляет модель цитировать исходную строку, а не придумывать оффер.

```text
Ты — аналитик маркетинга. На вход подаётся JSON с данными публичной страницы.
Верни ТОЛЬКО JSON-объект без markdown-обёртки по схеме:
{"items":[{"channel":"ads|social|seo","stage":"awareness|interest|decision",
"offer":"...","cta":"...","evidence":"точная строка из входных данных"}]}
Правила: не добавляй факты, которых нет во входном JSON; если данных для поля нет — null;
evidence обязательно и должно дословно совпадать с фрагментом входа.
```

**Что сделать:** отправить `page.json` в LLM и сохранить ответ.

```python
# funnel/<ваш-домен>/ask_llm.py
import json, os, urllib.request
from pathlib import Path

payload = json.loads(Path("out/page.json").read_text(encoding="utf-8"))
prompt  = Path("prompt.txt").read_text(encoding="utf-8")
body = json.dumps({
    "model": os.environ["LLM_MODEL"],
    "messages": [
        {"role": "system", "content": prompt},
        {"role": "user",   "content": json.dumps(payload, ensure_ascii=False)},
    ],
}).encode()

req = urllib.request.Request(
    os.environ["LLM_BASE_URL"].rstrip("/") + "/chat/completions",
    data=body,
    headers={"Authorization": "Bearer " + os.environ["LLM_API_KEY"],
             "Content-Type": "application/json"},
)
with urllib.request.urlopen(req, timeout=120) as r:
    ans = json.load(r)
text = ans["choices"][0]["message"]["content"]
Path("out/funnel.json").write_text(text, encoding="utf-8")
print("saved:", len(text), "символов")
```

Путь `/chat/completions` и структура ответа `choices[0].message.content` — формат OpenAI-совместимых API; если ваш провайдер устроен иначе, сверьтесь с его документацией.

**Как проверить:** ответ должен парситься как JSON и содержать записи с непустым `evidence`.

```bash
python3 -c "import json;d=json.load(open('funnel/<ваш-домен>/out/funnel.json'));\
print('записей:',len(d['items']));\
print('без evidence:',sum(1 for i in d['items'] if not i.get('evidence')))"
```

Ожидаемый вывод: `записей: 9` и `без evidence: 0`. Если вторая цифра больше нуля — повторите запрос с формулировкой «каждая запись обязана содержать evidence».

Собранные записи удобно свести в таблицу с колонками «Канал / Этап / Оффер / CTA / Доказательство»; как быстро собрать такую сводку в документе — разобрано в гайде [ChatGPT Office: как создавать документы и таблицы с помощью ИИ](https://ai-release.org/guides/chatgpt-office-kak-sozdavat-dokumenty-i-tablitsy-s-pomo.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide).

| Поле | Что писать | Откуда брать |
|---|---|---|
| channel | `ads`, `social` или `seo` | счётчики и разметка страницы |
| stage | `awareness`, `interest`, `decision` | тип CTA («Читать» → interest, «Купить» → decision) |
| offer | обещание клиенту одной фразой | `title`, `h1` |
| cta | текст кнопки дословно | массив `cta` |
| evidence | цитата из `page.json` | входные данные, дословно |

## Шаг 3. Сверить результат с источником и собрать отчёт
![Иллюстрация к разделу «Шаг 3. Сверить результат с источником и собрать отчёт»](https://ai-release.org/guides/img/kak-razobrat-marketingovuyu-voronku-konkurenta-po-ssylk-ru-3.jpg)


**Что сделать:** выборочно проверить, что каждая цитата `evidence` реально есть в скачанном HTML.

**Зачем:** это единственный способ поймать галлюцинацию (выдуманный факт) — модель могла «дописать» акцию, которой на странице нет.

```bash
grep -F -o "$(python3 -c "import json;print(json.load(open('funnel/<ваш-домен>/out/funnel.json'))['items'][0]['evidence'])")" \
  funnel/<ваш-домен>/raw/index.html
```

**Пример:** если `evidence` равно `Скидка 20% на первый заказ`, команда печатает эту же строку. Пустой вывод = цитаты на странице нет, запись надо удалить.

**Что сделать:** собрать итоговый файл `out/report.md` из проверенных записей и зафиксировать дату среза в имени папки (`funnel/<ваш-домен>-2025-06-01`).

**Зачем:** воронка конкурента меняется, и без даты через месяц невозможно понять, что изменилось — оффер или ваша ошибка.

**Как проверить:** чек-лист ниже должен быть полностью закрыт.

- [ ] `raw/index.html` весит больше 10 КБ
- [ ] `robots.txt` не содержит `Disallow: /`
- [ ] `out/funnel.json` парсится и содержит 0 записей без `evidence`
- [ ] каждая цитата находится через `grep -F`
- [ ] в `out/report.md` есть колонка «Доказательство» и дата среза
- [ ] в отчёте нет персональных данных из форм

Если результат нужно показать команде на созвоне, соберите из отчёта короткую колоду — приёмы описаны в гайде [Как создавать презентации с помощью ИИ: лучшие сервисы и советы](https://ai-release.org/guides/kak-sozdavat-prezentatsii-s-pomoschyu-ii-luchshie-servi.html?utm_source=tg&utm_medium=channel&utm_campaign=guide_inline&utm_content=guide_to_guide).

## Возможные проблемы и решения

**Проблема. curl скачивает пустой файл или страницу-заглушку**

- Ошибка: `< HTTP/2 403` в выводе `curl -sS -o /dev/null -w "%{http_code}\n" "https://<ваш-домен>/"` либо в `index.html` текст `Attention Required! | Cloudflare`
- Причина: сайт закрыт защитой от ботов (проверка User-Agent, JS-челлендж).
- Решение: не обходить защиту. Проверьте `robots.txt` и ToS; используйте официальные API площадки или ручной экспорт страницы через «Сохранить как → HTML полностью» и положите файл в `raw/index.html`. Дальнейшие шаги не меняются.

**Проблема. Модель вернула текст вместо JSON**

- Ошибка: `json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)`
- Причина: модель добавила пояснение или обернула ответ в ```` ```json ````.
- Решение: срезать обёртку перед записью в файл:

```bash
python3 -c "
import re,pathlib
t=pathlib.Path('funnel/<ваш-домен>/out/funnel.json').read_text(encoding='utf-8')
m=re.search(r'\{.*\}', t, re.S)
pathlib.Path('funnel/<ваш-домен>/out/funnel.json').write_text(m.group(0), encoding='utf-8')
print('cleaned')"
```

и в следующем запросе усилить инструкцию: «ответ должен начинаться с `{` и заканчиваться `}`».

**Проблема. sitemap не найден**

- Ошибка: `grep -c "<loc>"` возвращает `0`, а в файле видна HTML-страница с текстом `404 Not Found`
- Причина: sitemap лежит по другому адресу.
- Решение: найдите строку `Sitemap:` в `robots.txt` и скачайте указанный там URL:

```bash
grep -i "^sitemap:" funnel/<ваш-домен>/raw/robots.txt
curl -sSL "<URL-из-вывода>" -o funnel/<ваш-домен>/raw/sitemap.xml
```

## Резюме и следующие шаги
Вы получили воспроизводимый срез воронки конкурента: локальные копии публичных файлов, JSON-карту каналов и офферов с цитатами-доказательствами и отчёт с датой среза. Следующий шаг — повторить процедуру для 3–5 конкурентов из вашей ниши и сравнить колонку `channel`, чтобы увидеть, какие каналы они реально используют.

## FAQ

**Можно ли разобрать воронку без кода, только через чат с ИИ?**
Да, но проверяемость падает: вы вставляете текст страницы вручную и не сможете автоматически сверить цитаты через `grep -F`. Схема с `evidence` и локальными файлами надёжнее, потому что каждое утверждение модели проверяется одной командой.

**Законно ли собирать данные о рекламе и сайте конкурента?**
Собирать можно только публично доступные страницы, соблюдая `robots.txt` и ToS площадки. Не сохраняйте персональные данные из форм и не пытайтесь обходить защиту от ботов — при блокировке используйте официальные API или ручной экспорт.

**Почему ИИ пишет офферы и акции, которых нет на сайте?**
Потому что в промпте не было требования цитировать источник. Добавьте обязательное поле `evidence` с дословной строкой из входных данных и проверку `python3 -c "... sum(1 for i in d['items'] if not i.get('evidence'))"` — записи без цитаты удаляются.

**Как часто повторять такой разбор?**
Зависит от того, как часто конкурент меняет офферы и креативы; фиксированной нормы нет. Практично хранить каждый срез в папке с датой в имени и сравнивать отчёты между собой, не забывая про лимиты запросов к сайту и `robots.txt`.
