Всем привет! Во второй части мы продолжим забирать у «защищенного и дважды зашифрованного» Telegram сервера данные о подписчиках из открытых чатов.
Перед прочтением статьи настоятельно рекомендую ознакомиться с первой частью в ней мы создавали аккаунт разработчика Telegram и настраивали наш проект.
На данном этапе это всего один «.py» файл, настройки и файл сессии. Но, как говорит одна известная мудрость:
Делай хорошо — плохо само получится
Поэтому мы изначально будем делать наш проект как настоящие профи. Модулями
В этой части мы получим подписчиков открытого чата мессенджера и посмотрим, какие же сведения нам отдаст Телеграм
Переходим в PyCharm
Чтобы в дальнейшем не запутаться в нашем коде, мы создадим в директории проекта несколько файлов:
Users.py
links.txt
Весь наш код в этой главе мы будем писать именно в отдельном файле Users.py. Это существенно упростит нам работу в дальнейшем. Поверьте
Давайте импортируем этот файл в наш основной проект, который мы писали в первой части
import Users
Кроме того, для дальнейшей работы с пользователями чата нам понадобятся еще парочка импортов из нашей библиотеки Telethon
from telethon.tl.functions.channels import GetParticipantsRequest from telethon.tl.types import ChannelParticipantsSearch
Еще раз оговорюсь, что все импорты мы производим в нашем основном главном файле, который мы создавали в первой части «Update.py»
Для наглядности и удобства давайте установим в наш проект такую библиотеку как tqdm. Она позволит нам создавать в нашей консоли красивые читабельные Progress Bar ( графическую полоску прогресса нашей выгрузки )
Пишем команду pip install tqdm
Импортируем класс библиотеки в наш проект
from tqdm import tqdm
С импортами пока разобрались. Конечный итог наших импортов в основном файле выглядит так:
import configparser
from telethon import TelegramClient
import Users
from telethon.tl.functions.channels import GetParticipantsRequest
from telethon.tl.types import ChannelParticipantsSearch
from tqdm import tqdm
У нас остался непонятный нам файл links.txt, который мы с вами будем использовать как хранилище наших ссылок на чаты из которых будем парсить данные но об этом чуть дальше поговорим.
В нашем файле Users.py давайте создадим асинхронную функцию:
async def dump_all_participants(channel, ChannelParticipantsSearch,
client, GetParticipantsRequest, tqdm):
Имя функции вы можете выбирать любое, но стоит помнить, что мы с вами учимся делать хорошо. Не пугайтесь аргументов, здесь ничего сложного и страшного нету.
channel— это будет наш чат Телеграм который мы передадим в нашу функцию
ChannelParticipantsSearch и GetParticipantsRequest — это наши импорты которые мы делали выше они же классы библиотеки Telethon которые нам будут нужны в нашей функции.
tqdm — это наша библиотека для progress bar
client — это соответственно наше подключение которое мы создавали в первой части. Без него никак)
Теперь давайте настроим чтение ссылок на чаты из нашего файла links.txt
В нашем главном файле Update.py внутри функции main напишем такой код
async def main():
with open("links.txt", "r") as f:
while True:
try:
text = f.readline()
url = text
channel = await client.get_entity(url)
await Users.dump_all_participants(channel, ChannelParticipantsSearch,
client, GetParticipantsRequest, tqdm)
except Exception:
pass
Здесь, мы сразу после чтения файла будем вызывать нашу функцию «dump_all_participants» из файла Users.py.
Функция сбора пользователей чата Телеграм
Давайте наполним нашу функцию сбора пользователей кодом
Заходим в файл Users.py где мы создавали нашу функцию dump_all_participants
и пропишем константы для библиотеки Telethon
async def dump_all_participants(channel, ChannelParticipantsSearch,
client, GetParticipantsRequest, tqdm):
print('Сбор по каналу', channel.title)
OFFSET_USER = 0 # номер участника, с которого начинается считывание
LIMIT_USER = 200 # максимальное число записей, передаваемых за один раз но не более 200
ALL_PARTICIPANTS = [] # список всех участников канала
FILTER_USER = ChannelParticipantsSearch('') # фильтр для определенных пользователей
Фильтром для пользователей нам пользоваться не придется, но объявить и передать его в дальнейшем в качестве аргумента мы должны.
Создадим бесконечный цикл while:
while True:
participants = await client(GetParticipantsRequest(channel,
FILTER_USER, OFFSET_USER, LIMIT_USER,hash=0))
Мы передали запрос на получение списка пользователей нашего чата, который хранится в переменной channel.
В результате в переменной participants мы получим набор объектов библиотеки telethon, который содержит набор информации о каждом пользователе.
Пример данных пользователя из чата нашего паблика ВК
id=82197*****,
is_self=False,
contact=False,
mutual_contact=False,
deleted=False,
bot=False,
bot_chat_history=False,
bot_nochats=False,
verified=False,
restricted=False,
min=False,
bot_inline_geo=False,
support=False,
scam=False,
access_hash=79177640707*******8,
first_name=’Ar***a’,
last_name=В*****,
username=N*******,
phone=375294******,
photo=UserProfilePhoto(photo_id=35303467026******4, photo_small=FileLocationToBeDeprecated(volume_id=200397****55, local_id=278**5),
photo_big=FileLocationToBeDeprecated(volume_id=200397****55, local_id=27****), dc_id=2, has_video=False),
status=UserStatusRecently(),
bot_info_version=None,
restriction_reason=[],
bot_inline_placeholder=None,
lang_code=None
Для наглядности заранее пропишем запись полученных сведений в текстовый файл
Обязательно нужно указать кодировку, что бы избежать проблем с никами содержащими символы.
with open(f"{channel.title}.txt", "w", encoding="utf-8") as write_file:
for participant in tqdm(ALL_PARTICIPANTS):
try:
write_file.writelines(f" ID: {participant.id} "
f" First_Name: {participant.first_name}"
f" Last_Name: {participant.last_name}"
f" Username: {participant.username}"
f" Phone: {participant.phone}"
f" Channel: {channel.title} \n")
except Exception as e: # noqa
print(e)
print('Сбор по каналу завершен')
В нашем цикле for указываем наш итерируемый объект как аргумент функции tqdm.
Смотрим результат на примере первого попавшегося чата про Python
В корне нашей программы у нас появился файл {название канала}.txt который содержит сведения о пользователях
Для того, что бы запустить наш парсинг, в файл links.txt нужно вставить ссылку на чат или группу. Найти эту ссылку можно в описании любого чата.
ВАЖНО! Спарсить канал не получится т.к вы не являетесь его администратором.
прим. Автора
Ссылок на чаты может быть много. Важно писать их с новой строки.
Ура! Мы только что скачали список пользователей чата. Узнали их уникальные идентификаторы (id), что поможет нам в дальнейшем найти сообщения определённого пользователя в этом (либо в любом другом чате).
Об выгрузке сообщений из чата мы поговорим в следующей части.
Всем спасибо за внимание! Пишите о ваших впечатлениях в комментарии либо в наш паблик ВК
Полный код парсера Телеграм чатов
Файл Update.py
import configparser
from telethon import TelegramClient
import Users
from telethon.tl.functions.channels import GetParticipantsRequest
from telethon.tl.types import ChannelParticipantsSearch
from tqdm import tqdm
config = configparser.ConfigParser()
config.read("config.ini")
# Присваиваем значения внутренним переменным
api_id: str = config['Telegram']['api_id']
api_hash = config['Telegram']['api_hash']
username = config['Telegram']['username']
client = TelegramClient(username, api_id, api_hash)
client.start()
async def main():
with open("links.txt", "r") as f:
while True:
try:
text = f.readline()
url = text
channel = await client.get_entity(url)
print(url)
await Users.dump_all_participants(channel, ChannelParticipantsSearch,
client, GetParticipantsRequest, tqdm)
except Exception:
pass
with client:
client.loop.run_until_complete(main())
Файл Users.py
async def dump_all_participants(channel, ChannelParticipantsSearch,
client, GetParticipantsRequest, tqdm):
print('Сбор по каналу', channel.title)
OFFSET_USER = 0 # номер участника, с которого начинается считывание
LIMIT_USER = 200 # максимальное число записей, передаваемых за один раз но не более 200
ALL_PARTICIPANTS = [] # список всех участников канала
FILTER_USER = ChannelParticipantsSearch('') # фильтр для определенных пользователей
while True:
participants = await client(GetParticipantsRequest(channel,
FILTER_USER, OFFSET_USER, LIMIT_USER,
hash=0))
if not participants.users:
break
ALL_PARTICIPANTS.extend(participants.users)
OFFSET_USER += len(participants.users)
with open(f"{channel.title}.txt", "w", encoding="utf-8") as write_file:
for participant in tqdm(ALL_PARTICIPANTS):
try:
write_file.writelines(f" ID: {participant.id} "
f" First_Name: {participant.first_name}"
f" Last_Name: {participant.last_name}"
f" Username: {participant.username}"
f" Phone: {participant.phone}"
f" Channel: {channel.title} \n")
except Exception as e: # noqa
print(e)
print('Сбор по каналу завершен')
Подпишитесь на рассылку