├── README.md ├── config.py ├── parser.py ├── parser_functions.py └── requirements.txt /README.md: -------------------------------------------------------------------------------- 1 | # telegram channel parser 2 | Для того чтобы пользоваться данным парсером вам необходимо установить Python3 и несколько сторонних библиотек с помощью данной команды: 3 | 4 | На Windows: 5 | pip install -r requirements.txt 6 | 7 | На Mac OS и Linux: 8 | pip3 install -r requirements.txt 9 | 10 | Так же вам понадобится зарегистрировать собственное приложение Telegram. 11 | Для этого надо зайти на сайт https://my.telegram.org/apps, зайти в свою учётную запись Telegram и создать приложение 12 | (Create new application). 13 | Следует указать: 14 | - App title - название приложения (неважно какое) 15 | - Short name - сокращённое название (только буквы и цифры, 5-32 символа) 16 | - Platform - указать Other 17 | 18 | Остальные поля можно оставить пустыми. Нажать кнопку Create application. 19 | В этот момент зачастую Telegram не пускает вас дальше по непонятным причинам, но главное не сдаваться. 20 | Иногда помогает прокликивание без изменения данных, иногда надо поменять App title или Short name. 21 | После того как ваше приложение будет зарегистрировано откроется следующая страница на которой будут указаны 22 | регистрационные данные вашего приложения. Стоит сохранить все данные в надёжном месте, но для работы парсера 23 | вам понадобятся графы App api_id и App api_hash. Их надо вставить в одноимённые переменные в файле config.py. 24 | 25 | После установки библиотек и регистрации приложения, парсером можно пользоваться. 26 | Для этого: 27 | - зайдите в директорию с исходным кодом и вызовите парсер командой "python3 parser.py" 28 | - при первом запуске будет необходимо подтвердить вход через Telegram (двухфакторную аутентификацию лучше отключить на это время): 29 | - в консоли появится сообщение, после которого надо ввести номер телефона, привязанный к Telegram 30 | - после следующего сообщения ввести код подтверждения Telegram 31 | - вставить ссылку на канал в Telegram 32 | 33 | После получения ссылки сразу же начнётся сбор сообщений. 34 | В директории со скриптом появится папка с айди канала и журнал с расширением .log куда будут заносится отметки о работе скрипта. 35 | Внутри папки канала начнут появляться папки с названиями, соответствующими айди сообщения, а в них будет находится текстовый файл 36 | с текстом сообщения и зашитыми в него гиперссылками, а так же текстовый файл с "метаданными" - ссылкой на сообщение и датой и временем 37 | его отправки. Так же если к сообщению были приложены какие-либо медиа - они будут загружены в ту же папку. 38 | 39 | По умолчанию (при первом запуске) скрипт будет собирать сообщения за последние три месяца. Если же при повторном запуске в директории скрипта 40 | будет находится папка с ранне собранными сообщениями канала, то собраны будут только новые сообщения. 41 | 42 | Приятного пользования! 43 | 44 | -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | api_id = # введите API ID вашего приложения 2 | api_hash = "" # введите API Hash вашего приложения 3 | -------------------------------------------------------------------------------- /parser.py: -------------------------------------------------------------------------------- 1 | import logging # стандартная библиотека для логирования 2 | import parser_functions # библиотека этого парсера 3 | 4 | from telethon import TelegramClient, events, sync, connection # pip3 install telethon 5 | 6 | from config import api_id, api_hash # получение айди и хэша нашего приложения из файла config.py 7 | 8 | # настройка логгера 9 | logging.basicConfig( 10 | level=logging.INFO, 11 | filename='parser_log.log', 12 | filemode='w', 13 | format="%(asctime)s %(levelname)s %(message)s" 14 | ) 15 | 16 | logging.info("script started") # сообщение о начале работы в лог 17 | 18 | url = input() # получение ссылки на канал из консоли 19 | 20 | flag = True # флаг нужен для корректного логирования результата работы парсера (успешно/неуспешно) 21 | 22 | logging.info(f"parsing channel {url}") # сообщение об обрабатываемом канале в лог 23 | 24 | with TelegramClient('new', api_id, api_hash) as tc: # запуск клиента 25 | try: 26 | err = parser_functions.parse(tc, url) # обработка сообщений 27 | if err: # обработка возможных ошибок и запись их в лог 28 | logging.warning(err) 29 | else: # запись в лог об успешной работе при отсутствии ошибок 30 | logging.info("parsing done successfully") 31 | 32 | except Exception as ex: # обработка критической ошибки вроде ввода некорректной ссылки на канал, или отсутствия 33 | # доступа к каналу 34 | logging.critical(f"critical error {ex}") 35 | flag = False 36 | 37 | if flag: # запись в лог об успешной или неуспешной работе скрипта 38 | logging.info("script is done successfully") 39 | else: 40 | logging.warning("some errors occurred during script execution") 41 | -------------------------------------------------------------------------------- /parser_functions.py: -------------------------------------------------------------------------------- 1 | from telethon.tl.types import MessageEntityTextUrl 2 | from glob import glob 3 | from dateutil.relativedelta import relativedelta # pip3 install python-dateutil 4 | 5 | import datetime 6 | import os 7 | 8 | 9 | def get_channel_id(client, link): # получение ID канала 10 | m = client.get_messages(link, limit=1) 11 | channel_id = m[0].peer_id.channel_id 12 | return str(channel_id) 13 | 14 | 15 | def clearify_text(msg): # очищение текста от символов гиперссылки 16 | text = msg.message 17 | text_splitted = text.split() 18 | text_listed = [word for word in text_splitted if word != ' '] 19 | return " ".join(text_listed) 20 | 21 | 22 | def get_message_content(client, msg, url, channel_name, directory_name): # получение содержимого сообщения 23 | msg_date = str(msg.date) # дата отправки сообщения 24 | msg_url = url + '/' + str(msg.id) # каст ссылки на сообщение 25 | file = open(f"{channel_name}/{directory_name}/{directory_name}_meta.txt", 'a+') # запись метаданных сообщения 26 | file.write(msg_url) 27 | file.write('\n' + msg_date) 28 | file.close() 29 | if msg.message: # если сообщение содержит текст, запись этого текста в текстовый файл в папке сообщения 30 | text = clearify_text(msg=msg) 31 | file = open(f"{channel_name}/{directory_name}/{directory_name}.txt", "w") 32 | file.write(text) 33 | file.close() 34 | if msg.media: # если сообщение содержит медиа (фото, видео, документы, файлы), загрузка медиа в папку сообщения 35 | client.download_media(message=msg, file=f"{channel_name}/{directory_name}") 36 | if msg.entities: # запись гиперссылок из текста сообщения в файл сообщения 37 | urls = [ent.url for ent in msg.entities if isinstance(ent, MessageEntityTextUrl)] 38 | file = open(f"{channel_name}/{directory_name}/{directory_name}.txt", mode='a+') 39 | for u in urls: 40 | file.write('\n' + u) 41 | file.close() 42 | 43 | 44 | def find_last_parsed_date(path): # определение даты, с которой начинать парсинг 45 | paths = glob(f"{path}/*/*meta.txt", recursive=True) # поиск существующих метаданных по уже собранным сообщениям 46 | oldest = datetime.datetime.strptime("1970-01-01 00:00:00+00:00", "%Y-%m-%d %H:%M:%S%z") 47 | temp = oldest 48 | for p in paths: # поиск даты отправки последнего сообщения 49 | with open(p, 'r') as file: 50 | date = datetime.datetime.strptime(file.readlines()[-1], "%Y-%m-%d %H:%M:%S%z") 51 | if date > oldest: 52 | oldest = date 53 | if temp == oldest: 54 | oldest = datetime.datetime.now() - relativedelta(months=3) # если сообщений нет, офсет устанавливается на 55 | # три месяца от текущей даты 56 | return oldest 57 | 58 | 59 | def parse(client, url): # сбор сообщений из канала 60 | err = [] # переменная возможной ошибки 61 | channel_id = get_channel_id(client, url) # получение ID канала 62 | os.makedirs(channel_id, exist_ok=True) # создание папки канала в текущей директории 63 | oldest = find_last_parsed_date(channel_id) # получение даты, с которой начинать парсинг 64 | for message in client.iter_messages(url, reverse=True, offset_date=oldest): # итератор по сообщениям (урл - ссылка 65 | # на канал, реверс - итерация от старых 66 | # к новым, офсет - дата с которой 67 | # начинать парсинг 68 | try: 69 | directory_name = str(message.id) # получение ID сообщения 70 | os.makedirs(f"{channel_id}/{directory_name}", exist_ok=True) # создание папки сообщения 71 | get_message_content(client, message, url, channel_id, directory_name) # обработка сообщения 72 | 73 | except Exception as passing: # обработка ошибок 74 | err.append(passing) 75 | continue 76 | return err # возврат возможных ошибок 77 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | python-dateutil==2.8.2 2 | Telethon==1.28.5 --------------------------------------------------------------------------------