124 lines
7.0 KiB
Markdown
124 lines
7.0 KiB
Markdown
# parser-tg-bot
|
||
|
||
Парсер публичных Telegram-каналов на Telethon (MTProto). Сохраняет сообщения в Postgres,
|
||
управляется через REST API. Период опроса настраивается через `.env`. На следующем шаге
|
||
легко перевести на realtime через `events.NewMessage`.
|
||
|
||
## Стек
|
||
|
||
- Python 3.11, Telethon, FastAPI, SQLAlchemy 2 (async) + Alembic, APScheduler, Postgres 16
|
||
|
||
## Структура
|
||
|
||
```text
|
||
src/parser_bot/
|
||
├── api/ # FastAPI роуты + Pydantic-схемы
|
||
├── db/ # SQLAlchemy модели + сессии
|
||
├── scheduler/ # APScheduler-воркер периодического опроса
|
||
├── telegram/ # Telethon-клиент (resolve, fetch)
|
||
├── web/static/ # SPA-странички (HTML/CSS/JS, без бандлера)
|
||
├── config.py # pydantic-settings
|
||
└── main.py # FastAPI lifespan + uvicorn
|
||
alembic/ # миграции
|
||
```
|
||
|
||
## Первый запуск (локально, через Docker)
|
||
|
||
1. Получить `api_id` и `api_hash` на [my.telegram.org](https://my.telegram.org) → API development tools.
|
||
2. Скопировать `.env.example` в `.env` и заполнить `TG_API_ID`, `TG_API_HASH`, `TG_PHONE`.
|
||
3. Поднять Postgres + накатить миграции:
|
||
|
||
```bash
|
||
docker compose up -d db
|
||
docker compose run --rm app alembic upgrade head
|
||
```
|
||
|
||
4. Запуск:
|
||
|
||
```bash
|
||
docker compose up -d
|
||
docker compose logs app --tail=50
|
||
```
|
||
|
||
5. **Авторизация Telegram** — открыть [http://localhost:8000/auth.html](http://localhost:8000/auth.html)
|
||
и нажать «Отправить код». Telegram пришлёт код на номер из `TG_PHONE` →
|
||
ввести код (и 2FA-пароль, если включён). Готово, парсер начнёт опрос.
|
||
|
||
Сессия сохраняется в `./data/session/parser.session` — рестарты её переиспользуют,
|
||
повторно входить не нужно.
|
||
|
||
### Админ-доступ и коды подразделов
|
||
|
||
- `ADMIN_PASSWORD` — дополнительный пароль для админских функций. Если не задан,
|
||
остаётся прежний режим: доступ определяется только `ADMIN_ALLOWED_IPS`.
|
||
- [http://localhost:8000/admin.html](http://localhost:8000/admin.html) — вход по
|
||
админ-паролю. После входа доступны удаление и редактирование подразделов,
|
||
просмотр их кодов, управление каналами, ручной опрос, промпты, авторизация
|
||
Telegram и Swagger.
|
||
- При создании подраздела обязательно задаётся `Код доступа`. Пользователь вводит
|
||
этот код при первом открытии данных подраздела; после входа он может добавлять
|
||
каналы в этот подраздел. Админ видит код в списке подразделов.
|
||
|
||
### Прод-вариант: без UI и без volume (k8s-friendly)
|
||
|
||
Сделай интерактивный логин **один раз** на dev-машине и получи опаковую строку:
|
||
|
||
```bash
|
||
docker compose run --rm -it app python -m parser_bot.auth
|
||
```
|
||
|
||
Скрипт напечатает строку вида `TG_SESSION_STRING=1AbcD...`. Положи её в
|
||
`.env` или k8s Secret — после этого приложение поднимается без UI и без
|
||
монтирования сессионного файла:
|
||
|
||
```ini
|
||
TG_SESSION_STRING=1AbcDef... # вместо TG_SESSION_PATH/volume
|
||
```
|
||
|
||
> ⚠️ **`ApiIdPublishedFloodError`** — Telegram заблокировал твою пару
|
||
> `api_id`/`api_hash` (попала в публичный доступ). Создай **новое** приложение
|
||
> на [my.telegram.org](https://my.telegram.org) и не публикуй креды нигде.
|
||
> Старый `api_id` восстановить нельзя.
|
||
|
||
## UI
|
||
|
||
После запуска доступны страницы:
|
||
|
||
- [Дашборд](http://localhost:8000/) — общая статистика, топ каналов, кнопка опросить всех
|
||
- [Каналы](http://localhost:8000/channels.html) — добавить / удалить / включить-выключить / опросить вручную
|
||
- [Сообщения](http://localhost:8000/messages.html) — фильтр по каналу, поиск по тексту, пагинация, raw JSON
|
||
- [Настройки](http://localhost:8000/settings.html) — текущая конфигурация и подсказки
|
||
- [Авторизация](http://localhost:8000/auth.html) — веб-логин в Telegram (код + 2FA)
|
||
- [Swagger UI](http://localhost:8000/docs) — интерактивный API
|
||
|
||
Глубокая ссылка `messages.html?channel_id=42` открывает ленту конкретного канала.
|
||
|
||
## API
|
||
|
||
- `GET /healthz` — health check
|
||
- `GET /api/v1/auth/status` — авторизован ли клиент
|
||
- `POST /api/v1/auth/send-code` — отправить код на `TG_PHONE`
|
||
- `POST /api/v1/auth/submit-code` `{"code": "12345"}` — подтвердить код
|
||
- `POST /api/v1/auth/submit-password` `{"password": "..."}` — 2FA-пароль
|
||
- `POST /api/v1/auth/logout` — завершить сессию
|
||
- `GET /api/v1/stats` — глобальные счётчики
|
||
- `GET /api/v1/settings` — read-only вид конфигурации
|
||
- `GET /api/v1/channels` — список каналов
|
||
- `POST /api/v1/channels` `{"identifier": "@durov"}` — добавить
|
||
- `GET /api/v1/channels/{id}` — карточка
|
||
- `PATCH /api/v1/channels/{id}` `{"is_active": false}` — включить/выключить
|
||
- `DELETE /api/v1/channels/{id}` — удалить
|
||
- `GET /api/v1/channels/{id}/stats` — счётчики по каналу
|
||
- `POST /api/v1/channels/{id}/poll` — форсировать опрос одного канала
|
||
- `POST /api/v1/poll` — форсировать опрос всех активных каналов
|
||
- `GET /api/v1/messages?channel_id=...&q=...&limit=50&offset=0` — лента
|
||
- `GET /api/v1/messages/{id}` — одно сообщение (с `raw` JSONB)
|
||
|
||
## Дальше
|
||
|
||
- **Realtime**: заменить APScheduler на `client.add_event_handler(handler, events.NewMessage)`,
|
||
оставив periodic poll как фоновый «доводчик» для пропущенных сообщений.
|
||
- **Go-микросервис**: контракт = таблицы `channels` / `messages` в Postgres.
|
||
Go-сервис может либо читать ту же БД, либо ходить в `/api/v1/messages`.
|
||
- **k8s**: добавить Helm-чарт; `data/session/` маппится на PVC, `.env` — в Secret.
|