Парсинг Telegram-канала: Извлечение id комментаторов. Python + Telethon

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Аннотация

В статье приведён и разобран (полный и рабочий) скрипт, позволяющий автоматизированно собирать простую статистику о тг-канале: список id комментаторов с соответствующими количествами комментариев от каждого.

Введение

Всегда хочется взаимодействовать с потенциальными клиентами адресно и поименно, а не бить из пушки по воробьям. В этом плане подписчики потенциальных конкурентов - это очень ценный ресурс. Однако, список подписчиков тг-канала часто представляет собою священную тайну и просто так никто не станет делиться паствой трафиком. Поэтому получить конкретный список людей сложно, но вот комментаторов под постами никто не скрывает (возможно ли это?).
Конечно, можно вручную перебрать каждый пост и выписывать на листочек всех и каждого, но Telegram API позволяет автоматизировать этот процесс, что очень выручает, если анализируемых тг-каналов много, а постов сотни и тысячи.

Код

Актуальную версию кода можно получить в моём публичном репозитории. Сразу оговорюсь, что работа выполнялось в качестве учебной задачи по освоению python'а, поэтому слабонервных прошу отойти от экрана.

Скрипт целиком:

#====================================================================================================
import asyncio
from collections import Counter

import configparser

# класс для работы с сообщениями
from telethon import types
from telethon.sync import TelegramClient
#====================================================================================================


#====================================================
# Считываем учетные данные
config = configparser.ConfigParser()
config.read("config.ini")

# Присваиваем значения внутренним переменным
api_id   = config['Telegram']['api_id']
api_hash = config['Telegram']['api_hash']
username = config['Telegram']['username']

client = TelegramClient(username, api_id, api_hash)
#====================================================


#========================================================================================================
async def get_post_comments(channel_username, post_id, commentators, commentators_id):
    current_comment = {}
    try:
        async for message in client.iter_messages(channel_username, reply_to = post_id, reverse = True):
            print(str(post_id))
            sender = message.sender
            sender_id = message.from_id.user_id if message.from_id else None
            print(message.date, ':', message.text)
            if isinstance(sender, types.User):
                sender_name = sender.first_name if sender.first_name else "Unknown User"
                print(message.date, sender_name, ':', message.text)
                current_comment = {"date": message.date, "sender_name": sender_name, "message.text": message.text}
            elif sender is not None:
                sender_title = getattr(sender, 'title', 'Unknown Channel/Group')
                print(message.date, sender_title, ':', message.text)
                current_comment = {"date": message.date, "sender_name": sender_title, "message.text": message.text}
            else:
                print(message.date, 'Unknown Sender:', message.text)
                current_comment = {"date": message.date, "sender_name": 'Unknown Sender', "message.text": message.text}

            commentators.append(str(current_comment['sender_name']))
            commentators_id.append(str(sender_id))

            # Открытие файла в режиме добавления (append mode)
            with open('comments.txt', 'a') as file:
                file.write(
                        str(current_comment['date'])
                        + "  "
                        + str(current_comment['sender_name'])
                        + "  "
                        + str(current_comment['message.text'])
                        + '\n'
                        )
                
    except Exception as e:
        print(f'Error: {e}')

    finally:
        pass
#========================================================================================================


async def main():
    url = 'https://t.me/bogda2na_beads'
    await client.start()
    commentators = []
    commentators_id = []

    tasks = []
    for id in range(0, 481):
        tasks.append(get_post_comments(url, id, commentators, commentators_id))

    await asyncio.gather(*tasks)
    print("Запросы отправлены и ответы получены")
    counter = Counter(commentators)
    print(counter)
    counter_ids = Counter(commentators_id)
    print(counter_ids)

    # Открываем файл для добавления
    with open('commentators.txt', 'a', encoding='utf8') as file:
        for key, value in counter.items():
            file.write(f'{key} – {value}\n')

    # Открываем файл для добавления
    with open('commentators.txt', 'a', encoding='utf8') as file:
        for key, value in counter_ids.items():
            file.write(f'{key} – {value}\n')

with client:
    client.loop.run_until_complete(main())

Здесь можно выделить 4 блока:

  1. импорты;

  2. извлечение api_id, api_hash и username из файла config.ini; объявление client;

  3. функция записи комментария в текстовый файл, включая дату, имя и сам текст; функция также формирует список id комментаторов и список имен комментаторов;

  4. описание функции main, где происходит запись в файл искомого списка комментаторов.

Запросы в Telegram передаются асинхронно с помощью библиотеки asyncio. Без этого тоже можно, но о-о-очень медленно.
Использование config.ini оправдано соображениями безопасности и удобства: config.ini можно сразу добавить в gitignore и не переживать, что случайно закоммитишь что-то не то.
Блок с client.iter_messages нужно обязательно поместить в try-exception, потому что часто всплывает ошибка "Error: The message ID used in the peer was invalid (caused by GetRepliesRequest)". Она возникает из-за того, что не все посты можно комментировать. При итоговом выводе информации, эта ошибка будет просто проигнорирована.
Адрес тг-канала следует передавать в переменную url.
Результат дополняет, а не перезаписывает выходные текстовые файлы.

В результате работы будут сформированы два файла в каталоге проекта:

  1. comments.txt - содержит комментарии, которые стоят не в хронологическом порядке, потому что запросы в тг отправляются асинхронно, а результаты обрабатываются по готовности

  2. commentators.txt - содержит список имён и id пользователей с указанием, сколько раз они оставляли комментарии (в общей сложности, а не под одним или под разными постами).

Результат выглядит так:

commentators.txt

Светлана – 5
Unknown Sender – 44
Юля – 4
Elena – 11
Алена Кравец – 4
Bashmakov – 28
Заира – 1
тата – 10
Мария – 2
Anastasia – 1
Татьяна – 4
. – 1
Irina – 1
Елена – 4
Наташенька – 1
Куницына Маргарита – 3
Кирилл – 1
Юлианна Константиновна – 1

878607089 – 5
None – 44
894850931 – 4
423056916 – 11
714102368 – 4
797464942 – 28
563811537 – 1
2035908009 – 10
5223286129 – 2
690890125 – 1
412976784 – 4
852712534 – 1
1031395701 – 1
1009525902 – 4
884002074 – 1
6045087523 – 3
1237066481 – 1
5135131407 – 1

comments.txt

2024-03-07 18:07:59+00:00 Светлана Очень красиво!!!!!комплект отлично сочетается с джинсами!

Источник: https://habr.com/ru/articles/829580/


Интересные статьи

Интересные статьи

Универсальные типы в python, является незаменимым инструментом, который позволяет выявлять множество ошибок на моменте написания кода, а также делают код чище и элегантнее.Меня зовут Саша и в своей ра...
На Хабре уже была новость об этом знаменательном событии. Правда, она похожа на пересказ официального пресс-релиза Microsoft, но такой и должна быть "новость".
Бывают ситуации, когда нужно автоматизировать сбор и анализ данных из разных источников. Например, если хочется мониторить курс рубля в режиме реального времени. Для решения подобных задач применяют...
Следующий перевод подготовлен специально для «питонистов», которым интересно наверняка интересно почитать о новых функциях Python 3.8. В преддверии запуска нового потока по курсу «Разработчик Pyt...
Что важно для команды разработчиков, которая только начинает строить систему, базирующуюся на машинном обучении? Архитектура, компоненты, возможности тестирования с помощью интеграционных и юни...