Ошибки парсинга Telegram: баги кода или лимиты API
Разработка десктопного парсера Telegram на Python (PySide6 + Telethon + SQLite) часто сталкивается с двумя типичными проблемами: катастрофически медленная загрузка списка диалогов и блокировка базы данных SQLite. В этой статье мы детально разберём, вызваны ли эти ошибки ограничениями Telegram API или недочётами в коде, и дадим практические решения для каждого случая.
Почему список чатов загружается 30 минут через Telethon?
Медленная загрузка диалогов - частый симптом неправильной организации асинхронного цикла событий (event loop) в связке с PySide6. В вашем проекте asyncio работает в отдельном потоке, а GUI - в основном потоке Qt. Это может приводить к блокировкам, если вызовы Telethon не освобождают поток для обработки сигналов.
Основные причины замедления
- Конфликт циклов событий: PySide6 имеет свой собственный цикл событий (Qt event loop). Если asyncio loop не настроен на кооперацию с ним, запросы к API Telegram могут ожидать освобождения потока минутами.
- Отсутствие пагинации с лимитом: Telethon по умолчанию загружает все диалоги сразу. Если у аккаунта сотни чатов, каждый запрос может длиться до 30 секунд, а общее время суммируется.
- Лимиты Telegram API: Для обычных пользователей действует ограничение - не более 30 запросов в секунду на метод getDialogs. Превышение вызывает ожидание (sleep) до 30 минут.
Как ускорить? Используйте параметр limit в вызове client.get_dialogs(limit=50). Это сократит количество запросов. Также настройте асинхронный менеджер контекста: запускайте Telethon в отдельном потоке с собственным asyncio loop, изолированным от Qt, и передавайте результаты через сигналы.
Ошибка database is locked в SQLite при многопоточном парсинге
Ошибка database is locked возникает, когда несколько воркеров (парсинг, распознавание речи, экспорт) одновременно пытаются записать данные в SQLite. Даже с включённым WAL-режимом SQLite не поддерживает конкурентную запись из разных потоков без дополнительной синхронизации.
Почему WAL не спасает?
WAL (Write-Ahead Logging) позволяет одновременно читать данные из нескольких потоков, но запись всё равно блокируется: один писатель блокирует базу для других писателей. Если ваши воркеры вызывают INSERT или UPDATE одновременно, SQLite возвращает database is locked.
Решения
- Очередь запросов: Используйте единый поток для всех операций записи в SQLite. Воркеры отправляют данные через очередь (например,
queue.Queue), а отдельный писатель последовательно выполняет запросы. - Batch insert: Накопите 50-100 записей и вставляйте одним транзакционным запросом. Это снижает частоту блокировок.
- Пул соединений: Создайте одно глобальное соединение с SQLite с параметром
check_same_thread=Falseи используйте блокировку threading.Lock() для синхронизации доступа.
Нормальная ли скорость 100 сообщений за 5 минут?
Нет, это аномально медленно. При парсинге только текстовых сообщений Telethon способен обрабатывать 500-1000 сообщений в минуту на обычном интернет-соединении. Задержка в 5 минут на 100 записей указывает на проблему в коде: либо блокировка event loop, либо превышение API-лимитов с последующим длительным ожиданием. Проверьте, не вызываете ли вы await asyncio.sleep() без необходимости, и убедитесь, что в логах нет предупреждений о флуд-контроле (FloodWait).
Архитектура: как исправить конфликт asyncio и PySide6?
Для стабильной работы парсера рекомендуется разделить потоки чётко: основной поток - только GUI и PySide6 event loop; рабочий поток - свой asyncio loop для Telethon. Передача данных между ними - через Qt-сигналы (thread-safe). Пример настройки: создайте класс-воркер, который запускает asyncio.run() в отдельном потоке, а результаты эмитирует через сигнал finished.
Заключение
Обе проблемы - и медленная загрузка чатов, и блокировка SQLite - решаются правильной организацией потоков и синхронизацией. Telegram API не накладывает жёстких ограничений на скорость парсинга текстовых сообщений, поэтому виновник - код. Используйте лимиты запросов, очереди для записи в БД и изолируйте asyncio от Qt. Эти меры ускорят парсинг в 10-20 раз и устранят ошибки блокировки.