Каким образом связать получаемые из телеграма сообщения и находящиеся в них изображения (Telethon)

Рейтинг: 1Ответов: 1Опубликовано: 12.02.2023

Моя задача заключается в том, чтобы спарсить из двух телеграм каналов 10 сообщений со ссылками на содержащиеся в них изображения. Если брать изображение непосредственно из сообщения, таким образом: message.photo, то будет привязка только к первому изображению, при этом остальные изображения будут привязаны к пустым сообщениям. Пыталась связать через время следующим образом.

import json
import os
import datetime
from telethon.sync import TelegramClient
from telethon.tl.functions.messages import GetHistoryRequest



channels = ['Ozon Marketplace', 'Яндекс Маркет для продавцов']
client = TelegramClient('test', os.getenv('API_ID'), os.getenv('API_HASH'))

def main(phone):
    client.start()

    if not client.is_user_authorized():
        client.send_code_request(phone)
        client.sign_in(phone, input('Enter the code: '))
    offset_id = 0
    channels_data = []
    all_messages = []
    all_images = []
    limit = 10

    for channel in channels:
        channel_data = client.get_entity(channel)
        channels_data.append(channel_data)

        history = client(GetHistoryRequest(
                peer=channel_data,
                offset_id=offset_id,
                offset_date=None,
                add_offset=0,
                limit=limit,
                max_id=0,
                min_id=0,
                hash=0
            ))
        messages = history.messages
        for i in range(len(messages)):
            image_url = f'media/marketplace/{messages[i].photo.id}.png'
            image_date = messages[i].photo.date
            img_data = dict(model='mp_messages.image', pk=image_url, fields={'image_url': image_url,
                                                                             'date': image_date})
            message_data = dict(model='mp_messages.message', fields={})
            if messages[i].message:
                message_data['pk'] = messages[i].id
                message_data['fields']['date'] = messages[i].date
                message_data['fields']['message_text'] = messages[i].message
                if messages[i].photo is not None:
                    client.download_media(messages[i].photo, image_url)
                message_data['fields']['tag'] = channel
                all_messages.append(message_data)
                img_data['fields']['message_id'] = messages[i].message
                #
                for img in all_images:
                    if abs(messages[i].date - img['fields']['date']).seconds <= 5:
                        img['fields']['message_id'] = messages[i].message
            else:
                for message in all_messages:
                    if abs(message['fields']['date'] - img_data['fields']['date']).seconds <= 5:
                        img_data['fields']['message_id'] = message['fields']['message_text']
            all_images.append(img_data)
    with open('mp_messages/fixtures/channel_messages.json', 'w') as outfile:
        json.dump(all_messages, outfile, ensure_ascii=False, default=str)
    with open('mp_messages/fixtures/channel_images.json', 'w') as outfile:
        json.dump(all_images, outfile, ensure_ascii=False, default=str)
    return all_images


print(main(os.getenv('PHONE')))

Ответы

▲ 1Принят

Проблема получения первого изображения вместо всех связана с тем, что messages[i].photo возвращает только первую фотографию в сообщении, и если в сообщении несколько фотографий, вам необходимо получить к ним доступ через messages[i].media.

Вот обновленная версия вашего кода, которая должна иметь возможность загружать все изображения в сообщении:

import json
import os
import datetime
from telethon.sync import TelegramClient
from telethon.tl.functions.messages import GetHistoryRequest

channels = ['Ozon Marketplace', 'Яндекс Маркет для продавцов']
client = TelegramClient('test', os.getenv('API_ID'), os.getenv('API_HASH'))

def main(phone):
    client.start()

    if not client.is_user_authorized():
        client.send_code_request(phone)
        client.sign_in(phone, input('Enter the code: '))
    offset_id = 0
    channels_data = []
    all_messages = []
    all_images = []
    limit = 10

    for channel in channels:
        channel_data = client.get_entity(channel)
        channels_data.append(channel_data)

        history = client(GetHistoryRequest(
                peer=channel_data,
                offset_id=offset_id,
                offset_date=None,
                add_offset=0,
                limit=limit,
                max_id=0,
                min_id=0,
                hash=0
            ))
        messages = history.messages
        for i in range(len(messages)):
            message_data = dict(model='mp_messages.message', fields={})
            if messages[i].message:
                message_data['pk'] = messages[i].id
                message_data['fields']['date'] = messages[i].date
                message_data['fields']['message_text'] = messages[i].message
                message_data['fields']['tag'] = channel
                all_messages.append(message_data)

                # download all photos in message
                for photo in messages[i].media.photo:
                    image_url = f'media/marketplace/{photo.id}.png'
                    image_date = photo.date
                    img_data = dict(model='mp_messages.image', pk=image_url, fields={'image_url': image_url,
                                                                                     'date': image_date,
                                                                                     'message_id': messages[i].id})
                    client.download_media(photo, image_url)
                    all_images.append(img_data)
            else:
                for message in all_messages:
                    for photo in messages[i].media.photo:
                        if abs(message['fields']['date'] - photo.date).seconds <= 5:
                            image_url = f'media/marketplace/{photo.id}.png'
                            img_data = dict(model='mp_messages.image', pk=image_url, fields={'image_url': image_url,
                                                                                             'date': photo.date,
                                                                                             'message_id': message['fields']['message_text']})
                            all_images.append(img_data)
    with open('mp_messages/fixtures/channel_messages.json', 'w') as outfile:
        json.dump(all_messages, outfile, ensure_ascii=False, default=str)
    with open('mp_messages/fixtures/channel_images.json', 'w') as outfile:
        json.dump(all_images, outfile, ensure_ascii=False, default=str)
    return all_images

print(main(os.getenv('PHONE')))

Этот код должен быть способен загружать все изображения в сообщении, даже если в одном сообщении есть несколько фотографий. Он также включает идентификатор сообщения в данные изображения, чтобы вам было легче сопоставлять изображения с сообщениями.