Как я написал скрипт для экспорта Telegram-диалогов за 2 дня
Date: 2026-02-26 Stack: Python 3.12, Telethon 1.37, Claude Code (Opus) Duration context: 2 дня, 9 рабочих сессий
Зачем это нужно
Есть менеджеры по продажам, которые ведут клиентов через Telegram. Десятки, сотни диалогов. Руководитель хочет понять: как работает менеджер, какие вопросы задают клиенты, где воронка протекает. Но Telegram не даёт нормального экспорта переписок — только свой формат через встроенный “Export chat history”, и то по одному чату.
Задача: написать инструмент, который подключается к Telegram-аккаунту менеджера и выгружает все диалоги с клиентами в один JSON-файл, пригодный для анализа.
Что получилось
CLI-утилита на Python. Запускается через .bat, работает из консоли. Никакого веб-интерфейса — только терминал и JSON на выходе.
Ключевые фичи:
- Мультиаккаунт — система профилей, каждый со своей сессией, конфигом и папкой данных
- QR-авторизация — не нужно вводить номер и код, просто сканируешь QR с телефона
- Инкрементальная загрузка — при повторном запуске качает только новые сообщения
- Smart skip — если в диалоге нет новых сообщений, пропускает его вообще без API-вызова
- Обход FloodWait — автоматический retry с рандомной паузой при блокировке от Telegram
- Фильтрация — только диалоги с реальными людьми, без ботов и групп
Как устроен проект
project/
├── main.py # Точка входа: авторизация, загрузка диалогов, JSON-экспорт
├── profile_manager.py # CRUD профилей, интерактивное меню
├── config.py # Легаси-конфиг (миграция в профили)
├── start.bat # Лаунчер с UTF-8
├── profiles/
│ ├── _active.txt # Активный профиль
│ └── {name}/
│ ├── config.json # api_id, api_hash, phone, 2fa
│ ├── session.session # Telethon-сессия (SQLite)
│ └── data/{user_id}/dialogs.json
Один dialogs.json на аккаунт. Внутри — массив диалогов, в каждом — массив сообщений с метаданными: дата, отправитель, текст, реакции, медиа-тип, ответы, пересылки.
С какими проблемами столкнулись
1. SMS-код не приходит при авторизации
Симптом: вводишь номер телефона — код не приходит. Ни через SMS, ни через встроенное уведомление Telegram.
Причина: Telethon по умолчанию не показывает подробности подключения. Непонятно, дошёл ли запрос вообще.
Решение: Включили DEBUG-логирование Telethon. Оказалось, что проблема в формате номера. После этого добавили QR-авторизацию как основной метод — она надёжнее и не требует SMS.
2. Сессия не сохраняется между запусками
Симптом: авторизовался по QR, всё работает. Перезапустил скрипт — снова просит авторизацию.
Причина: файл session.session (SQLite-файл Telethon) не находился по правильному пути при использовании системы профилей.
Решение: Явно указали путь к сессии при создании TelegramClient, привязав его к директории профиля.
3. FloodWaitError при массовой выгрузке
Симптом: при попытке выгрузить 300+ диалогов Telegram блокирует запросы на N секунд.
Причина: Telegram жёстко лимитирует частоту запросов к API — примерно 40 сообщений в секунду.
Решение: Три уровня защиты:
flood_sleep_threshold=120в клиенте Telethon — автоматически ждёт при FloodWait до 2 минут- Ручной retry с
sleep(e.seconds + random jitter)до 3 попыток - Рандомная пауза 1-3 секунды между диалогами
4. Takeout API — казалось хорошей идеей
Симптом: для массового экспорта (80+ диалогов) попробовали Takeout API — официальный механизм Telegram для выгрузки данных. Crashes, ошибки TakeoutInitDelayError.
Причина: Takeout API требует подтверждения на телефоне пользователя. Каждый раз. Это неприемлемо для автоматизации.
Решение: Отказались от Takeout полностью. Обычный метод с паузами и retry работает надёжно даже для 300+ диалогов — просто медленнее.
5. Повторная загрузка уже скачанных диалогов
Симптом: каждый запуск скрипта заново качал все сообщения из всех диалогов. При 200+ диалогах это занимало часы.
Решение: Двухуровневая оптимизация:
- Smart skip: сравниваем
dialog.message.id(ID последнего сообщения в диалоге) с сохранённым максимальным ID. Если совпадает — диалог не изменился, пропускаем без единого API-вызова. - Incremental download: если диалог изменился, используем параметр
min_idвget_messages(), чтобы загрузить только новые сообщения. Старые остаются в JSON, новые мерджатся.
Результат: повторный запуск для 200 диалогов, из которых изменилось 5 — занимает секунды вместо часов.
Ключевые решения
Telethon, а не Pyrogram
Рассматривали оба варианта. Pyrogram привлекал встроенной поддержкой QR-авторизации. Но Telethon оказался более зрелым, QR-авторизацию реализовали через него без проблем, а документация и сообщество у Telethon значительно больше.
Профили вместо одного конфига
Изначально был один config.py. Но когда появилась задача выгружать данные с нескольких аккаунтов — перешли на систему профилей. Каждый профиль = отдельная папка с конфигом, сессией и данными. Миграция со старого формата — автоматическая при первом запуске.
JSON, а не база данных
Сознательный выбор. JSON легко открыть, легко загрузить в любой инструмент анализа, легко передать. Для задачи “выгрузить и проанализировать” — это оптимальный формат. Если бы нужен был real-time доступ или поиск — выбрали бы SQLite.
Инсайты
-
QR-авторизация надёжнее SMS. Не зависит от оператора, не требует ввода кода, работает мгновенно. Для любых Telegram-инструментов — рекомендую как основной метод.
-
Smart skip — must have. Без него инструмент бесполезен для регулярного использования. Сравнение одного числа (message ID) экономит сотни API-вызовов.
-
Takeout API переоценён. Для автоматизации он не подходит — требует ручного подтверждения. Обычные методы с грамотным rate limiting работают не хуже.
-
Claude Code написал 90% кода. Весь проект — от первой строки до финальной полировки — был создан в Claude Code за 9 сессий. Человек формулировал задачи, тестировал, направлял. ИИ писал код, дебажил, рефакторил.
Источники
- Telethon Documentation — основная библиотека проекта
- Telegram API Rate Limits — официальные лимиты Telegram API
- Telethon QR Login Example — документация по авторизации
Что дальше
Скрипт решает первую часть задачи — сбор данных. Вторая часть — анализ — делается уже в Claude AI, куда загружается полученный JSON. Об этом — в следующей статье.