Автоматизированный инструмент лидогенерации для малого бизнеса. Парсит Яндекс.Карты, находит заведения с негативными отзывами по конкретным болям (запись, ожидание, хамство, потеря клиента) и генерирует персонализированный скрипт холодного диалога под каждый лид.
Результат: готовый текст первого сообщения в WhatsApp/Telegram — деловой, конкретный, без рекламного тона. Упоминает реальную ситуацию из отзыва клиента.
Яндекс.Карты
│
▼
[scraper_yandex.py] ── headless Chromium, обходит JS-рендеринг
│
├─ фильтр: рейтинг 3.0–4.6 ★, есть WhatsApp или Telegram
│
▼
[card_cache.py] ── кэш ~800+ карточек, повторный запуск не парсит заново
│
▼
[dialog_gen.py] ── классификация боли → детерминированный MSG1
│
└─ опционально: LM Studio (Gemma 4) улучшает формулировку
│
▼
output/leads_*.txt ── структурированный лид с контактами и скриптом
Скрипт не ищет просто плохие отзывы — он определяет конкретную проблему, под которую составляется уникальное первое сообщение:
| Тип | Что означает | Пример отзыва |
|---|---|---|
no_response |
Не берут трубку / не перезванивают | «не дозвонился, так и не записался» |
no_show |
Пришёл — заведение закрыто | «приехал по записи, дверь закрыта» |
cancellation |
Отменили/перенесли без предупреждения | «запись отменили, не сообщили» |
waiting |
Ждал больше 30 минут | «опоздали на час, не извинились» |
lost_booking |
Запись потерялась | «пришёл — в расписании нет» |
phone_rude |
Нагрубили по телефону | «оператор накричал» |
wrong_result |
Сделали не то, что просили | «просил не трогать виски — обкарнали» |
general |
Общее недовольство | всё остальное |
[no_response]
Видел отзыв у вас в Краснодаре — клиент пишет, что не смог дозвониться,
так и не записался. В часы пик часто такое?
[cancellation]
Видел отзыв у вас — запись перенесли или отменили, но клиенту не сообщили.
Это вручную приходится всех обзванивать?
[wrong_result]
Видел отзыв у вас — клиент просил одно, мастер сделал иначе.
Пожелания при записи как-то фиксируете, или всё устно?
Ни одно сообщение не содержит слов «предлагаем», «автоматизация», «бот». Тон — коллега, который заметил что-то в отзыве, не продавец.
├── _fast5.py # быстрый прогон: 5 лидов по 40+ городам
├── _run_leads_new.py # полный прогон: 20 лидов
├── scraper_yandex.py # парсер Яндекс.Карт (headless Playwright)
├── scraper_2gis.py # парсер 2ГИС (альтернатива)
├── scraper_google.py # парсер Google Maps
├── dialog_gen.py # классификация боли + генерация скрипта
├── card_cache.py # JSON-кэш карточек (output/cache_parsed.json)
├── models.py # BusinessCard, Review, Phone
├── analyzer.py # анализ собранных данных
├── export_leads.py # экспорт лидов
├── messages.py # шаблоны сообщений
├── main.py # CLI-точка входа (парсинг через config.json)
├── config.json # конфиг задач
├── requirements.txt
└── output/
├── cache_parsed.json # кэш (не коммитится)
├── leads_fast5.txt # результаты быстрого прогона
└── leads_new_20.txt # результаты полного прогона
git clone https://github.com/feewwee39-dev/lead-parser.git
cd lead-parser
pip install -r requirements.txt
playwright install chromium$env:PYTHONUTF8="1"
python -X utf8 _fast5.pyРезультат записывается в output/leads_fast5.txt в реальном времени.
tail -f output/_fast5_log.txt$env:PYTHONUTF8="1"
python -X utf8 _run_leads_new.py| Параметр | Значение | Описание |
|---|---|---|
CITIES |
40+ городов | Краснодар, Воронеж, Самара, Уфа, Архангельск и др. |
RATING_MIN / RATING_MAX |
3.0 – 4.6 | Ищем тех, у кого есть проблемы, но не провальных |
MIN_NEG / MAX_NEG |
1 – 6 | Минимум 1 негативный отзыв, не более 6 |
MAX_REVIEWS |
15 | Сколько отзывов читать с карточки |
NEED |
5 | Сколько лидов нужно найти за прогон |
| Задержка | 0.2–0.4 с | Между карточками (anti-ban) |
| URL на город | 30 | Максимум карточек на поисковый запрос |
Обязательное условие лида: наличие WhatsApp или Telegram у заведения.
Если запущен LM Studio с любой локальной моделью — скрипт автоматически улучшает формулировку MSG1, сохраняя деловой стиль. При недоступности LM Studio используется детерминированный шаблон (работает не хуже).
LM_HOST = "http://localhost:1234"
LM_MODEL = "local-model"Протестировано с Gemma 4 (27B). Модель настроена на однострочный ответ без рассуждений.
────────────────────────────────────────────────────────────────────────
ЛИД #1 [WA+TG] | Barber Culture | Тамбов | *4.0
Адрес : ул. Советская, 153
Тел : +7 920 000-00-00
WA : https://wa.me/79200000000
TG : https://t.me/barberculture
Ссылка : https://yandex.ru/maps/...
Запись : только звонки/мессенджеры
Негативных: 2 | боль: 1
НЕГАТИВНЫЕ ОТЗЫВЫ:
1. *2 Иван К. [БОЛЬ]
Просил не трогать виски — мастер обкарнал до нуля. На замечание
ответил что "так лучше выглядит".
БОЛЬ: «просил не трогать виски — мастер обкарнал»
СКРИПТ:
........................................................................
Видел отзыв у вас — клиент просил одно, мастер сделал иначе.
Пожелания при записи как-то фиксируете, или всё устно?
........................................................................
| Слой | Технология |
|---|---|
| Парсинг | Python 3.12 + Playwright (async, headless Chromium) |
| Источники | Яндекс.Карты, 2ГИС, Google Maps |
| Кэш | JSON (~800+ карточек, персистентный между запусками) |
| NLP | Детерминированная классификация по ключевым словам |
| LLM (опц.) | LM Studio / OpenAI-совместимый API (локально) |
| Вывод | Структурированный TXT с полным скриптом диалога |
Инструмент создан для холодных продаж Telegram мини-приложения записи барбершопам и салонам (1 500 ₽ под ключ). Скрипт находит заведения, где уже есть подтверждённая боль в отзывах, и формирует первое сообщение, которое попадает в конкретную проблему — не шаблонный спам.
Воронка: парсер → MSG1 (боль) → MSG2 (вопрос о текущей записи) → MSG3 (уточнение) → MSG4 (питч) → MSG5 (демо за 1 минуту).