Как написать парсер телеграм‑каналов на Python

В предыдущей статье об асинхронном программировании на Python мы разобрали основные моменты, связанные с построением асинхронного приложения и функций. Теперь рассмотрим полезный пример, который вовсю использует принципы асинхронности, — простой парсер данных из Telegram

Содержание статьи

async for

Чтобы пример с парсером был понятнее, сначала поговорим про циклы внутри асинхронных функций. Вспомним финальный пример из первой части статьи, посвященной асинхронному программированию на Python, с получением данных о погоде:

Добавим еще одну функцию, которая будет отображать прогресс измерения давления:

Теперь, если мы запустим приложение, будем видеть прогресс измерения давления:

Все хорошо отрабатывает и проблем нет. Но пойдем дальше в сторону реальных условий работы. Бывает, что функции отдают не готовую последовательность, а асинхронный генератор или асинхронный итератор. Это специальные контейнеры, которые содержат в себе данные и при каждом обращении асинхронно выдают по одному объекту.

Перепишем функцию процесса измерения:

Раз функция def ticker( ) теперь является генератором, то мы должны каждый раз его вызывать, когда она нам понадобится. Классический способ перебора всех значений, возвращаемых генератором, — это подстановка его вызова в цикл for. Перепишем функцию измерения давления:

Теперь, если запустим код, столкнемся с интересной ошибкой:

Исходя из текста может показаться, что генератор не является итерируемым объектом. Но на самом деле проблема здесь в другом. Мы работаем с асинхронным генератором, а значит и цикл, который его перебирает, тоже должен быть асинхронным:

Все снова отлично работает! Зачем это нужно, спросите вы? Прямо сейчас и узнаем.

Как написать парсер телеграм-каналов на Python

Основы языка Python
Курс для всех, а не только для IT-специалистов
Смотреть программу

Telegram — один из самых популярных источников контента. Каналов в мессенджере столько, что следить за всеми самостоятельно просто нереально, не говоря уж про использование и анализ получаемой информации. Но зачем все делать вручную, когда за нас это может сделать приложение? Совместим приятное с полезным: напишем приложение для парсинга данных из любого телеграм-канала и параллельно закрепим тему асинхронных компонентов.

Шаг 1. Создаем приложение API для Telegram

Для начала необходимо завести аккаунт в Telegram, если его еще нет. Затем переходим по ссылке https://my.telegram.org/auth и авторизуемся с помощью номера телефона.

Код подтверждения придет прямо в мессенджере Telegram. Необходимо его ввести в поле Confirmation code:

В открывшемся окне переходим по ссылке API Development Tools. Вас перебросит в окно создания приложения. Необходимо заполнить основные поля:

Значения полей можно указывать любые. Для нас они не играют особой роли. Ставим точку напротив Desktop. И подтверждаем заполнение кнопкой Create application.

Следующее окно отобразит важные параметры вашего приложения, которые нам и будут нужны для создания приложения на Python. Это App api_id и App api_hash

Шаг 2. Устанавливаем библиотеку Telethon

Теперь у нас есть все необходимое, чтобы приступить к созданию приложения в Python. Первым делом нам понадобится библиотека telethon, чтобы авторизоваться и получить доступ к данным аккаунта. Устанавливаем ее обычным способом:

Далее импортируем необходимые модули и сразу создадим переменные с данными для авторизации:

Естественно, в серьезных приложениях авторизационные данные не хранятся в таком открытом виде. Обычно используются переменные окружения, содержимое которых не раскрывается.

Следующий шаг — авторизация приложения и создание сессионного файла. Допишем следующую строку:

Здесь 'test_tg' — это название файла, который будет создан для хранения авторизационных данных приложения. Далее необходимо создать тот самый цикл обработки событий (event loop). Это будет асинхронная функция main( ), в которой мы пока напишем команду-заглушку pass. И сразу запустим этот цикл, используя один из методов запуска библиотеки telethon:

Теперь наше приложение необходимо запустить, чтобы пройти одноразовую авторизацию. Примерно так же вы устанавливаете приложение на компьютер и авторизуете его с помощью QR-кода. Запустите приложение — и в окне терминала увидите приглашение ввести проверочный код:

Можно ввести номер телефона — тогда следующее сообщение попросит одноразовый код, который придет в Telegram:

Если все выполнили верно, то ниже в терминале получите сообщение:

А также в списке файлов появится файл с авторизационными данными, имеющий расширение *.session Готово! Все последующие запуски вашего приложения уже будут выполняться без запроса одноразовых паролей. И код, написанный в обработчике событий main( ), будет сразу исполняться.

Шаг 3. Получаем первые данные из Telegram

Настало время сбора данных. Начнем с того, что у telethon есть неплохая документация, основные методы из которой мы и рассмотрим. Первая информация, которая нам доступна, — о нашем аккаунте:

Если проверим тип полученного объекта, то увидим знакомое:

Мы получаем корутину. То есть все методы клиента Telegram асинхронны. Еще бы: без асинхронности мы не смогли бы получать информацию одновременно из нескольких чатов, а отправка фотографии другу вообще застопорила бы все процессы на глобальном уровне.
Поэтому все методы вызываем только через await:

Полученный объект me содержит огромное количество свойств, включая ваше имя, фамилию, номер телефона, фотографию и много еще чего персонального, что афишировать не нужно. Просмотреть содержимое объекта удобно в режиме отладки:

Шаг 4. Получаем диалоги

Чтобы получить список диалогов, воспользуемся еще одним методом клиента .get_dialogs( )

В dialogs получим общее количество диалогов, которое включает не только каналы, на которые мы подписаны, но и личные переписки. Можете посмотреть их количество в отладчике или воспользоваться функцией len(dialogs) и получить шок от итогового количества. У меня 1540 диалогов:

Зачем специалисту Python
Бесплатный вебинар в Контур.Школе
Смотреть

Так как в dialogs нам, по сути, возвращается итерируемый объект, мы можем легко его перебрать с помощью обычного цикла for, чтобы найти именно тот канал или переписку, которые нам нужны.

Каждый элемент полученного dialogs — это объект класса Dialog библиотеки telethon. Посмотреть методы и свойства этого объекта можно в документации. Переберем диалоги по названиям и найдем нужный:

Шаг 5. Получаем сообщения из выбранного канала

Убедитесь, что нужный канал находится и вы получаете об этом сообщение. Когда канал у вас на руках, можно получить из него все сообщения, которые когда-либо были написаны.

Воспользуемся методом client.iter_messages(dialog), чтобы получить сообщения: 

  • Важно посмотреть на тип полученного значения у messages:

Получаем не готовый список, как в случае с диалогами, а итератор. Это не должно быть проблемой, потому что элементы итератора мы можем получить так же, как и у списка, — закинуть в цикл for:

Если теперь запустим приложение, то текстов сообщений мы не увидим, а получим ошибку:

Это именно то, о чем мы говорили в самом начале: нужен асинхронный for, чтобы перебирать элементы асинхронного итератора. Исправим эту ошибку и получим желаемый результат:

 Единственное, что рекомендуется добавить, — обычную задержку между чтением каждого сообщения во избежание блокировок вашего аккаунта со стороны сервисов Telegram. Пусть будет медленно, зато спокойно и уверенно.

Напоследок рекомендуем также ознакомиться со всеми свойствами и методами объекта message. Основные, которые могут пригодиться при сборе полных данных, вынесены в таблицу:

date Свойство Содержит дату сообщения
edit_date Свойство Содержит дату редактирования сообщения
file Свойство Содержит файл, который приложен к сообщению
download_media( ) Метод Позволяет загрузить файл, приложенный к сообщению
is_reply Свойство Показывает, является ли сообщение ответом на другое сообщение
forward Свойство Содержит информацию о первоисточнике, если текущее сообщение было переслано

Конечно, в разных ситуациях могут потребоваться разные данные, но у этой статьи нет цели перепечатать всю документацию библиотеки telethon. На этой полезной ноте мы и завершим наше знакомство с асинхронным миром программирования. 

628
Планируйте обучение с максимальной выгодой для себя и для бизнеса
Узнать подробнее