Бот парсит фриланс/инфобиз-чаты через 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 │ │
│ └──────────────┘ │
└─────────────────────────────────────────────────────┘
- Polling (
_poll_loop, каждые 30с): обходит все чаты-источники - Фильтрация (
is_vacancy): антиспам (~90 regex-паттернов) → если совпало = НЕ вакансия - Позитивные сигналы (
VACANCY_SIGNALS): «ищу», «нужен», «оплата» и т.д. → порог = 1 совпадение - Дедупликация: SHA-256 хеш первых 500 символов (normalized) → проверка в БД (
vacancies.text_hash) - Классификация (
classify_vacancy): матчинг по профессиям (keyword-based) - Рассылка (
_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 # ← этот файл
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()→ фильтрация → классификация → broadcastjoin_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
~90 regex-паттернов, проверяются через re.search(). Если хотя бы один совпал — сообщение НЕ вакансия.
Категории:
| Категория | Примеры паттернов |
|---|---|
| MLM / сетевой маркетинг | сетевой бизнес, пассивный доход, партн[её]рская программа |
| Продажа услуг (фрилансеры) | чем могу быть полезна, мои услуги, готова взять проект |
| Самопрезентация / резюме | ищу работу, ищу подработку, рассмотрю вакансии, компетенции: |
| Агентства | мы подключаем отдел продаж, что мы предлагаем, в наш пакет услуг |
| Скам-вакансии | возраст 18\+, наличие карты рф, зп ежедневно, nft.*менеджер |
| «Без опыта» / обучение | без опыта, обучу с нуля, с обучением и поддержкой, всему научу |
| Дропы | ищем дропов, % за.*оборот |
| Инфопродукты | без вложений, пройти тест.драйв, ты снова это пролистаешь |
| Системные | ваше сообщение удалено, ознакомьтесь с правилами |
Принцип: «Лучше пропустить пару вакансий, чем спамить пользователей» (Алексей).
Keyword-based матчинг. Поддерживает как подстроки, так и regex.
Профессии: Таргетолог, СММ, Копирайтер, Дизайнер, ВебДизайнер, Маркетолог, Разработчик, Видеомонтажёр, Менеджер проектов, Ассистент, Методолог, Продюсер, Фотограф, Аналитик, Продажи
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
- Домен: https://vacancy.automateme.ru
- Порт: 8080 (внутренний)
- Volumes:
bot-data:/app/data(БД + сессия Pyrogram) - Auto-deploy: push в
main→ Coolify пересобирает и деплоит
git push origin main # Coolify подхватит автоматически- Push в GitHub → Coolify деплоит
- Бот отправит админу сообщение «Введите код авторизации»
- Код придёт в Telegram (раздел «Входы» / Saved Messages)
- Отправить
/code XXXXXботу - Если 2FA:
/password пароль - Добавить источники:
/add_sources+ список
| Переменная | Описание |
|---|---|
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
mari_vakansii
profiwork
frilanc
https://t.me/rueventjob4at
@smmvakancii
+xxPv8gKoffwxNzNi
Поддерживает: username, @username, https://t.me/username, invite-ссылки.
- Встроены в aiogram через
pre_checkout_query+successful_payment - Тарифы: week / month / quarter
- Настраиваются через
/set_price
- 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 |
- FloodWait: слишком много запросов кодов. Подождать 1-2 часа.
- Код не приходит: проверить раздел «Входы» в Telegram (не SMS, а in-app).
- SessionPasswordNeeded: нужен
/password <пароль>.
- Проверить
/stats→ «Мониторинг: ✅ Запущен» - Проверить
/sources→ чаты подключены (✅) - Проверить
/recent→ сообщения из чатов видны - Логи:
[POLL],[MSG],[VACANCY],[BROADCAST],[SEND]
- Скриншот → анализ паттерна → добавить regex в
SPAM_SIGNALS(config.py) - Валидация:
python3 -c "import ast; ast.parse(open('bot/config.py').read())" - Commit + push → Coolify автодеплоит
- Файл:
/app/data/bot.db(в Docker volumebot-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/крипто/авито.