Skip to content

zverror/vacancy-bot

Repository files navigation

Vacancy Bot — Telegram-бот мониторинга вакансий

Бот парсит фриланс/инфобиз-чаты через Pyrogram userbot, классифицирует сообщения по профессиям и рассылает подходящие вакансии подписчикам через aiogram.

Оглавление


Архитектура

┌─────────────────────────────────────────────────────┐
│                  VACANCY BOT                         │
│                                                      │
│  ┌──────────────┐    ┌───────────────────────────┐  │
│  │  aiogram Bot  │    │   Pyrogram Userbot        │  │
│  │  (порт 8080)  │    │   (polling каждые 30с)    │  │
│  │               │    │                           │  │
│  │  /start       │    │  get_chat_history()       │  │
│  │  /profile     │    │       ↓                   │  │
│  │  /subscribe   │    │  is_vacancy() → антиспам  │  │
│  │  /admin       │    │       ↓                   │  │
│  │  /add_source  │    │  classify_vacancy()       │  │
│  │  /add_sources │    │       ↓                   │  │
│  │               │    │  dedup (SHA-256 hash)     │  │
│  │  Webhook:     │    │       ↓                   │  │
│  │  /webhook/    │    │  broadcast → подписчикам  │  │
│  │  yumoney      │    │                           │  │
│  └──────┬───────┘    └───────────┬───────────────┘  │
│         │                        │                   │
│         └────────┐  ┌────────────┘                   │
│                  ▼  ▼                                │
│            ┌──────────────┐                          │
│            │  SQLite DB   │                          │
│            │  /app/data/  │                          │
│            │  bot.db      │                          │
│            └──────────────┘                          │
└─────────────────────────────────────────────────────┘

Поток данных

  1. Polling (_poll_loop, каждые 30с): обходит все чаты-источники
  2. Фильтрация (is_vacancy): антиспам (~90 regex-паттернов) → если совпало = НЕ вакансия
  3. Позитивные сигналы (VACANCY_SIGNALS): «ищу», «нужен», «оплата» и т.д. → порог = 1 совпадение
  4. Дедупликация: SHA-256 хеш первых 500 символов (normalized) → проверка в БД (vacancies.text_hash)
  5. Классификация (classify_vacancy): матчинг по профессиям (keyword-based)
  6. Рассылка (_broadcast_vacancy): отправка подписчикам, у которых совпадают профессии + активна подписка/триал

Стек

Компонент Технология
Bot API aiogram 3.x
Userbot/Парсер Pyrogram 2.x + TgCrypto
БД SQLite (aiosqlite)
HTTP aiohttp (webhook ЮMoney)
Деплой Docker + Coolify
Хостинг VPS Алексея (vacancy.automateme.ru)
Репозиторий github.com/zverror/vacancy-bot

Структура файлов

vacancy-bot/
├── bot/
│   ├── __init__.py
│   ├── config.py              # Конфигурация + PROFESSIONS + VACANCY_SIGNALS + SPAM_SIGNALS
│   ├── database.py            # SQLite схема + все CRUD-операции
│   ├── main.py                # Точка входа: запуск aiogram + userbot + webhook
│   ├── handlers/
│   │   ├── __init__.py
│   │   ├── admin.py           # Админские команды (/admin, /stats, /sources, /add_source, /add_sources, etc.)
│   │   ├── help.py            # /help
│   │   ├── profile.py         # /profile — выбор профессий
│   │   ├── start.py           # /start — регистрация + онбординг
│   │   └── subscription.py    # /subscribe — тарифы + оплата Stars
│   ├── monitor/
│   │   ├── __init__.py
│   │   ├── classifier.py      # is_vacancy() + classify_vacancy()
│   │   └── userbot.py         # VacancyMonitor — Pyrogram polling, join/leave, broadcast
│   └── payments/
│       ├── __init__.py
│       └── yukassa.py         # ЮMoney webhook handler
├── chat-analysis/             # Скрипты анализа чатов-источников
│   ├── FINAL_REPORT.md        # Финальный отчёт: 46 рекомендованных из 167
│   ├── recommended.xlsx       # Excel-таблица рекомендованных
│   └── ...
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
├── .env.example
└── README.md                  # ← этот файл

Компоненты

1. VacancyMonitor (bot/monitor/userbot.py)

Pyrogram-клиент, работает в polling-режиме (НЕ через dispatcher/on_message).

Ключевые методы:

  • start()client.connect() → авторизация (send_code / sign_in)
  • _poll_loop() → каждые 30с вызывает _poll_all_chats()
  • _poll_chat(chat_id)get_chat_history() → фильтрация → классификация → broadcast
  • join_source(ref) → подписка + авто-архивация + мут (чтобы не мешало владельцу)
  • leave_source(ref) → отписка
  • check_subscriptions() → каждые 5 мин проверяет, подписан ли на все источники
  • _archive_and_mute(chat_id) → отправляет в Архив (folder_id=1) + мут навсегда

Авторизация Pyrogram:

  • Админ отправляет /code <код> боту → submit_code()
  • Если 2FA: /password <пароль>submit_password()
  • Сессия сохраняется в /app/data/pyrogram_session.session

2. Антиспам (config.pySPAM_SIGNALS)

~90 regex-паттернов, проверяются через re.search(). Если хотя бы один совпал — сообщение НЕ вакансия.

Категории:

Категория Примеры паттернов
MLM / сетевой маркетинг сетевой бизнес, пассивный доход, партн[её]рская программа
Продажа услуг (фрилансеры) чем могу быть полезна, мои услуги, готова взять проект
Самопрезентация / резюме ищу работу, ищу подработку, рассмотрю вакансии, компетенции:
Агентства мы подключаем отдел продаж, что мы предлагаем, в наш пакет услуг
Скам-вакансии возраст 18\+, наличие карты рф, зп ежедневно, nft.*менеджер
«Без опыта» / обучение без опыта, обучу с нуля, с обучением и поддержкой, всему научу
Дропы ищем дропов, % за.*оборот
Инфопродукты без вложений, пройти тест.драйв, ты снова это пролистаешь
Системные ваше сообщение удалено, ознакомьтесь с правилами

Принцип: «Лучше пропустить пару вакансий, чем спамить пользователей» (Алексей).

3. Классификация (config.pyPROFESSIONS)

Keyword-based матчинг. Поддерживает как подстроки, так и regex.

Профессии: Таргетолог, СММ, Копирайтер, Дизайнер, ВебДизайнер, Маркетолог, Разработчик, Видеомонтажёр, Менеджер проектов, Ассистент, Методолог, Продюсер, Фотограф, Аналитик, Продажи

4. Дедупликация

SHA-256 хеш первых 500 символов текста (нормализован: lowercase + strip). Хранится в vacancies.text_hash. Одинаковые вакансии из разных чатов не дублируются.


База данных

SQLite (/app/data/bot.db), WAL-режим.

Таблицы:

Таблица Назначение
users Пользователи (user_id, username, trial_end, sub_end)
user_professions Выбранные профессии пользователя (M2M)
vacancies Найденные вакансии (source_chat, message_id, text, professions, text_hash)
sent_vacancies Отправленные вакансии (user_id, vacancy_id) — трекинг
payments Платежи (user_id, plan, amount, method)
sources Чаты-источники (chat_ref, added_at)
settings Настройки (key-value, включая тарифы)

Миграции:

  • text_hash колонка: добавляется через ALTER TABLE при старте, если отсутствует
  • Правило: ВСЕГДА ALTER TABLE ADD COLUMN, никогда не менять CREATE TABLE

Деплой

Coolify (автодеплой из GitHub)

  • Домен: https://vacancy.automateme.ru
  • Порт: 8080 (внутренний)
  • Volumes: bot-data:/app/data (БД + сессия Pyrogram)
  • Auto-deploy: push в main → Coolify пересобирает и деплоит

Ручной деплой:

git push origin main  # Coolify подхватит автоматически

Первый запуск:

  1. Push в GitHub → Coolify деплоит
  2. Бот отправит админу сообщение «Введите код авторизации»
  3. Код придёт в Telegram (раздел «Входы» / Saved Messages)
  4. Отправить /code XXXXX боту
  5. Если 2FA: /password пароль
  6. Добавить источники: /add_sources + список

Конфигурация

Переменные окружения (.env):

Переменная Описание
BOT_TOKEN Токен aiogram бота (@orf_vacancy_bot)
API_ID Pyrogram API ID (из my.telegram.org)
API_HASH Pyrogram API Hash
PHONE Номер телефона для userbot (+79208693683)
ADMIN_IDS ID админов через запятую (5094009390)
DB_PATH Путь к SQLite (data/bot.db)
LOG_LEVEL Уровень логов (INFO)

Админские команды

Команда Описание
/admin Показать панель со всеми командами
/stats Статистика: пользователи, подписки, вакансии, платежи
/sources Список подключённых источников (✅/⏳)
/add_source <chat> Добавить один источник
/add_sources Массовое добавление (каждая строка = 1 источник)
/del_source <chat> Удалить источник
/recent 10 последних сообщений из источников
/test_vacancy Тест классификатора на примере
/analyze Выгрузка 200 сообщений из каждого чата в JSON
/prices Текущие тарифы
/set_price <plan> <rub> <stars> Изменить тариф
/broadcast <текст> Рассылка всем пользователям
/code <код> Код авторизации Pyrogram
/password <пароль> 2FA пароль Pyrogram

/add_sources — массовое добавление:

/add_sources
mari_vakansii
profiwork
frilanc
https://t.me/rueventjob4at
@smmvakancii
+xxPv8gKoffwxNzNi

Поддерживает: username, @username, https://t.me/username, invite-ссылки.


Платежи

Telegram Stars

  • Встроены в aiogram через pre_checkout_query + successful_payment
  • Тарифы: week / month / quarter
  • Настраиваются через /set_price

ЮMoney

  • Webhook: POST /webhook/yumoney (порт 8080)
  • НЕ ЮKassa — это ЮMoney (разные API)
  • Обработчик: bot/payments/yukassa.py (название файла историческое)

Ключевые решения

Решение Почему
Polling вместо on_message client.connect() не запускает dispatcher Pyrogram; polling через get_chat_history надёжнее в Docker
POLL_INTERVAL = 30с Баланс скорость/нагрузка
Порог вакансии = 1 сигнал Антиспам уже отсёк мусор; 1 позитивного сигнала достаточно
Хеш первых 500 символов Дедупликация без хранения полного текста
Авто-архивация + мут Чтобы 50+ чатов-источников не засоряли Telegram владельцу аккаунта
Без хардкода источников Только через /add_source и БД — гибкость
Антиспам > классификация Сначала отсекаем мусор, потом ищем сигналы
«Без опыта» = спам Целевая аудитория — опытные специалисты; «без опыта» = MLM/скам или нерелевант

Креденшелы

Что Значение
Bot username @orf_vacancy_bot
Bot ID 8701125806
Bot token 8701125806:AAEs95J4XeD5yVCP8nqZiN5cWlSlrSdhhCc
Pyrogram API ID 33225356
Pyrogram API Hash 523bd3894be515aed60cd08025b770e4
Pyrogram phone +79208693683
Pyrogram user Alex G²
Admin ID 5094009390 (@who_is_the_captain)
GitHub github.com/zverror/vacancy-bot
Домен vacancy.automateme.ru
Coolify Автодеплой из main

Частые проблемы

Pyrogram не авторизуется

  • FloodWait: слишком много запросов кодов. Подождать 1-2 часа.
  • Код не приходит: проверить раздел «Входы» в Telegram (не SMS, а in-app).
  • SessionPasswordNeeded: нужен /password <пароль>.

Вакансии не приходят

  1. Проверить /stats → «Мониторинг: ✅ Запущен»
  2. Проверить /sources → чаты подключены (✅)
  3. Проверить /recent → сообщения из чатов видны
  4. Логи: [POLL], [MSG], [VACANCY], [BROADCAST], [SEND]

Спам проскакивает

  1. Скриншот → анализ паттерна → добавить regex в SPAM_SIGNALS (config.py)
  2. Валидация: python3 -c "import ast; ast.parse(open('bot/config.py').read())"
  3. Commit + push → Coolify автодеплоит

БД повреждена

  • Файл: /app/data/bot.db (в Docker volume bot-data)
  • WAL-режим: bot.db-wal и bot.db-shm — не удалять
  • Бэкап: sqlite3 bot.db ".backup backup.db"

История коммитов (ключевые)

Хеш Описание
bf3070e Переход на polling (с on_message)
533f2c3 Фикс regex + снижение порога до 1
ae0ef06 Убраны хардкод SOURCE_CHATS
5d4673e Дедупликация по text_hash
7e7741d Антиспам: агентства
5a2d515 Антиспам: скам-вакансии + самопрезентация
e35bab4 Антиспам: «без опыта»
ad07e71 /add_sources — массовое добавление
25ca8f2 Антиспам: дропы + резюме
c49bc5f Авто-архивация + мут при подписке

Анализ чатов-источников

Проведён 05.03.2026. Из 167 публичных чатов отобрано 46 качественных источников.

Полный отчёт: chat-analysis/FINAL_REPORT.md Excel-таблица: chat-analysis/recommended.xlsx

Критерии отбора: реальные вакансии от работодателей, тематика инфобиз/фриланс/SMM/дизайн, >500 участников, активность, без MLM/крипто/авито.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors