├── 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
--------------------------------------------------------------------------------