Как получить доступ к огромным массивам текстов из Telegram, чтобы изучать язык медиа, тренды или реакцию общества на события в мире? В этом помогут Telegram Desktop, Python и библиотека pyrogram. В гайде с кодом рассказываем о методе «цепной реакции» для поиска и скачивания целых групп связанных каналов. Превратите Telegram в ваш исследовательский полигон!
Иллюстрация: Ксения Здоровец
Современные гуманитарные исследования все чаще обращаются к большим массивам текстов как к основному источнику знаний о жизни общества. Если раньше такими источниками были письма, газеты и интервью, то сегодня на смену им пришли цифровые платформы — прежде всего, социальные сети и мессенджеры (подробнее об этом в первом выпуске блога Дмитрия Пронина). Именно здесь язык существует в своей «естественной среде»: формируется спонтанно, без редактуры, отражает эмоции, реакции и динамику событий в реальном времени.
Для журналистики, социологии, политологии и других прикладных дисциплин это открывает уникальные возможности. Исследователь может количественно оценить медиасреду вокруг конкретной фигуры, будь то политик, предприниматель или инфлюенсер. Это позволяет проследить, какие темы и формулировки доминируют в обсуждениях, что меняется после громких высказываний или событий. Более того, появляется возможность фиксировать реакцию аудитории на социальные и политические инициативы, выявлять тренды и сдвиги в общественном настроении.
Особую роль в этом контексте играет мессенджер Telegram — один из крупнейших коммуникационных сервисов, объединяющий на 2025 год более 1 млрд пользователей (по месячному пользованию, MAU) по всему миру. Он служит площадкой для разнообразных медиа: от официальных СМИ и политических каналов до локальных сообществ и анонимных микроблогов. Это делает Telegram ценным источником эмпирических данных для изучения языка и дискурса.
В этой статье вы узнаете, как извлекать и структурировать данные из Telegram для анализа.
Сначала рассмотрим, как можно работать с отдельными каналами. Сперва нам понадобится компьютер с установленным приложением Telegram Desktop.
Запустите Telegram Desktop, перейдите в интересующий вас канал и нажмите на три точки в правом верхнем углу. В выпадающем меню выберите пункт «Экспорт истории чата».
Рис. 1. Кнопка «Экспорт истории чата»
Перед вами появится окно с настройками. Снимите галочки с изображений, файлов, голосовых и прочих вложений. Нас интересует только текст. Внизу выберите формат данных JSON — он простой и гибкий и при этом универсально машиночитаемый, Python понимает JSON. Укажите путь, по которому нужно сохранить данные, и нажмите «Экспортировать».
Для пользователей Apple и MacOS: учтите, что опция отсутствует в той версии Telegram Desktop, которая доступна в AppStore. Чтобы воспользоваться ею, установите версию приложения с сайта самого Telegram.
Рис. 2. Окно настроек экспорта
Через несколько минут (в зависимости от объема) Telegram создаст папку с названием вроде ChatExport_2025-06-18. В этой папке будет лежать файл result.json, именно он нам и нужен.
Рис. 3. Содержимое папки с результатами выгрузки истории чата
Напишем код на python для обработки полученного JSON-файла:
import pandas as pd
# Загружаем JSON-файл
# (укажите полный путь до result.json, если он не в одной папке с кодом)
df = pd.read_json("result.json")
# Раскрываем содержимое колонки messages
messages = pd.json_normalize(df["messages"])
# Оставляем только сообщения с типом 'message'
messages = messages[messages["type"] == "message"]
# Функция, которая поможет корректно выгрузить сообщения
def get_text(row):
parts = []
if isinstance(row["text"], list):
for item in row["text"]:
if isinstance(item, dict) and "text" in item:
parts.append(item["text"])
elif pd.notnull(row["text"]):
parts.append(str(row["text"]))
if pd.notnull(row.get("caption", None)):
parts.append(str(row["caption"]))
return "\n".join(parts).strip()
# Применим эту функцию к DataFrame
messages["text"] = messages.apply(get_text, axis=1)
# Оставляем только строки, где текст не пустой
messages = messages[messages["text"] != ""]
# Оставляем только нужные колонки
result = messages[["date", "text"]]
# Сохраняем в Excel
result.to_excel("result.xlsx", index=False) Теперь в нашей таблице result.xlsx хранятся сообщения из Telegram в удобном для анализа виде. Эти данные можно изучать прямо в Excel: искать слова и выражения, фильтровать сообщения, выделять интересующие фрагменты. При необходимости таблицу можно снова открыть в Python с помощью библиотеки pandas и функции read_excel, чтобы применить более гибкие инструменты анализа.
На этом этапе уже можно начать работать с текстом, например, выделить ключевые слова, оценить плотность публикаций по времени и среднюю длину сообщений, построить вероятностные модели встречаемости слов, провести тональный анализ или тематическое моделирование.
Таким образом, экспорт истории чата Telegram позволяет работать с отдельными каналами (или даже с вашей личной перепиской) как с текстовыми корпусами. Однако во многих исследованиях этого недостаточно. Если мы хотим получить более полную и статистически значимую картину, необходимо расширить масштаб — выйти за рамки одного канала и охватить большее количество источников.
Здесь возникает ключевая проблема: в Telegram отсутствует полноценный поиск по существующим каналам и группам, как, например, в VK. Попасть в большинство из них можно только по прямой ссылке. Это затрудняет построение выборки и делает невозможным простой сбор большого массива данных.
Чтобы понять, как выгрузить множество каналов разом, сначала нужно разобраться с тем, как выгрузить хотя бы один канал полностью в автоматическом режиме. В этом нам поможет python с его библиотекой pyrogram, разработанной специально для взаимодействия с Telegram.
Сначала установим эту библиотеку через командную строку:
pip install pyrogram tgcrypto Теперь для взаимодействия с Telegram нам нужно получить ключи доступа. Перейдите на официальный сайт мессенджера и авторизуйтесь, введя свой номер телефона. Вам придет сообщение в Telegram с кодом для входа. После авторизации станет доступен раздел API Development tools: откройте его, создайте новое приложение, получите и сохраните ваши api_id и api_hash. Если не получилось, обратитесь к гайду, где процесс создания приложения и получения ключей описан более подробно.
Напишем функцию, которая позволит нам автоматизировать выгрузку:
# Импортируем необходимые библиотеки
from pyrogram import Client
from pyrogram.errors import FloodWait, ChannelPrivate # Обрабатываем частые ошибки при работе с Telegram
import pandas as pd # Для создания и сохранения таблиц
import os # Для работы с файлами и папками
import datetime # Для работы с датами
import time # Для задержки в случае ошибки
from tqdm import tqdm # Для отображения прогресса в цикле
# Указываем данные для подключения к Telegram API
api_id = 'ВАШ_API_ID'
api_hash = 'ВАШ_API_HASH'
# Создаем Telegram-клиент с именем сессии "my_session"
# При первом запуске вас попросят ввести номер телефона и код из Telegram
app = Client("my_session", api_id=api_id, api_hash=api_hash)
# Функция для парсинга одного Telegram-канала
def parse_channel(channel_link, cutoff_date):
posts = [] # сюда будут собираться сообщения (дата и текст)
found_links = [] # сюда будут собираться ссылки на другие каналы
# Открываем сессию Telegram-клиента
with app:
# Получаем историю сообщений указанного канала
for message in app.get_chat_history(channel_link):
# Получаем дату публикации сообщения
message_date = message.date.date()
# Если сообщение старше указанной даты - прекращаем цикл
if message_date < cutoff_date:
break
# Если в сообщении есть текст - сохраняем его
if message.text:
posts.append({
'date': message.date.strftime('%d.%m.%Y'),
'text': message.text
})
# Сохраняем подпись к изображению или документу
elif message.caption:
posts.append({
'date': message.date.strftime('%d.%m.%Y'),
'text': message.caption
})
# Сохраняем репосты и метаданные групп, из которых они сделаны
if message.forward_from_chat:
found_links.append({
'username': message.forward_from_chat.username,
'title': message.forward_from_chat.title
})
# Создаем таблицу pandas из собранных сообщений, удаляя дубли
posts_df = pd.DataFrame(posts).drop_duplicates(ignore_index=True)
# Создаем таблицу pandas из найденных ссылок, удаляя дубли
links_df = pd.DataFrame(found_links).drop_duplicates(ignore_index=True)
# Возвращаем две таблицы: с сообщениями и с найденными каналами
return posts_df, links_df Теперь снова выгрузим Telegram-канал «Системного Блока» и сохраним полученный DataFrame в формате Excel.
# Выбираем дату, начиная с которой будут выгружаться сообщения
cutoff_date = datetime.datetime.strptime("01.01.2019", "%d.%m.%Y").date()
# Производим выгрузку
posts_df, links_df = parse_channel(channel_link='sysblok', cutoff_date=cutoff_date)
posts_df.to_excel('sysblok.xlsx', index=False) Обратим внимание на то, что функция parse_channel возвращает две переменных: posts_df — DataFrame с постами самого канала, а также links_df — таблицу со ссылками на каналы, из которых были сделаны репосты. Так, например, на момент написания этого предложения «Системный Блокъ» ссылался на канал Татьяны Шавриной Kali Novskaya (rybolos_channel) и канал проекта «Пишу тебе» (pishuteberu).
Этими ссылками можно воспользоваться, чтобы запустить «цепную реакцию» (т. е. рекурсивное выкачивание новых каналов, поиск репостов и далее по кругу)! Если повторить описанную выше операцию с Kali Novskaya и «Пишу тебе», мы также с большой вероятностью найдем репосты и таким образом получим ссылки на несколько новых каналов. С ними затем можно будет проделать все то же самое.
Рис. 4. Рекурсивное расширение нашего поиска позволяет находить по ссылкам и выгружать всё новые и новые каналы — так мы получаем доступ к практически неограниченным объемам данных
Теоретически, если среднее число новых, неизвестных до этого ссылок на каждой итерации будет больше одной (часто так и происходит), «цепная реакция» выгрузки данных остановится только тогда, когда скачает весь Telegram.
В реальности, разумеется, будут существовать каналы, на которые никто никогда не ссылался, или циклы-острова, за пределы которых цепная реакция не вырвется. Анализ подобных случаев — тема для отдельной статьи.
Реализуем описанный «цепной» алгоритм на практике. Сначала создадим следующие файлы и папки в папке проекта:
Поместим в файл parser.py функцию для автоматической выгрузки и код ниже, реализующий один шаг «цепной реакции» (рекурсии):
# Загрузка ссылок на каналы из файла
channels_df = pd.read_excel('tg_links.xlsx')
channel_links = channels_df['link'].tolist()
# Проверка уже загруженных каналов
downloaded_channels = [os.path.splitext(file)[0] for file in os.listdir('data')]
cutoff_date = datetime.datetime.strptime("01.01.2020", "%d.%m.%Y").date()
new_channels = []
for link in tqdm(channel_links):
if link not in downloaded_channels:
try:
posts_df, links_df = parse_channel(link, cutoff_date)
# Сохраняем сообщения канала в JSON
posts_df.to_json(f'data/{link}.json',
force_ascii=False, indent=2)
# Сохраняем найденные ссылки сразу в удобном формате CSV
if not links_df.empty:
links_df.to_csv(f'reserved_links/{link}_found_links.csv',
index=False, encoding='utf-8')
new_channels.extend(links_df.to_dict('records'))
print(f'Канал {link} обработан. Сообщений: {len(posts_df)}, найдено ссылок: {len(links_df)}.')
except ChannelPrivate:
print(f"Канал {link} приватный, пропускаем.")
except FloodWait as e:
print(f"Превышено количество запросов, ждем {e.value} секунд.")
time.sleep(e.value)
except Exception as e:
print(f"Неизвестная ошибка при обработке канала {link}: {e}")
else:
print(f'Канал {link} уже загружен.')
# Добавляем новые найденные каналы в таблицу и сохраняем
if new_channels:
new_channels_df = pd.DataFrame(new_channels)
updated_channels_df = pd.concat([channels_df, new_channels_df.rename(columns={'username':'link', 'title':'name'})])
updated_channels_df.drop_duplicates(subset='link', inplace=True, ignore_index=True)
updated_channels_df.to_excel('tg_links.xlsx', index=False)
print("Обработка завершена, таблица ссылок обновлена.") Перед запуском обязательно создайте Excel таблицу tg_links.xlsx или скачайте ее шаблон по ссылке. Для корректной работы алгоритма таблица должна иметь всего два столбца с названиями link и name.
Рис. 5. Столбцы в таблице tg_links.xlsx
После запуска алгоритм совершает один шаг «цепной реакции»: он загружает все Telegram-каналы, указанные в исходной таблице, и ищет в них упоминания других каналов. Все найденные ссылки сохраняются в ту же таблицу tg_links.xlsx, расширяя таким образом исследуемую сеть.
Каждый загруженный канал сохраняется в формате JSON в папке data, текст постов становится доступен для дальнейшего анализа. С помощью стандартных инструментов, таких как библиотека pandas в Python, эти данные можно использовать, например, для построения частотных таблиц, графов упоминаний или временных рядов на основе сообщений.
Благодаря механизму «цепной реакции» можно собрать базу данных из тысяч каналов, связанных между собой упоминаниями, — фактически сформировать фрагмент медиасреды с ее внутренними связями и динамикой.
Такая база может служить основой для широкого спектра исследований. Вы можете:
Вооружившись документацией pyrogram, можно расширить функционал алгоритма, например, выгружать только каналы с определенным числом подписчиков, скачивать комментарии к постам (которые редко бывают действительно информативными из-за обилия рекламных ботов) или даже сохранять прикрепленные картинки и видео.
Источники: Документация pyrogram. URL: https://docs.pyrogram.org (дата обращения 30.06.2025).
Компания Google представила много новых ИИ-продуктов, а модель GPT опровергла известную математическую гипотезу Пала Эрдёша — рассказываем, что произошло в мире ИИ за последнее время
Facebook* и Instagram* будут сканировать фото и видео, чтобы находить детей, которые скрыли свой возраст
Можно ли заниматься NLP, если при словах «производная» и «матрица» хочется закрыть ноутбук? Да — если изучать математику не абстрактно, а через реальные задачи. Объясняем, какие разделы действительно нужны джуну,…