@magnuis_juma

Как сохранить более одного медиа при парсинге канала через telethon?

у меня есть бот-автопостер и модуль парсера. мне нужно сохранять последний пост из искомого канала на комп и постить в список каналов channels.json (только от имени бота, вариант отправки сообщения пользователем через сессию не подойдет). сейчас парсер может сохранить не более одного медиа + текст, когда он пытается спарсить сообщение в котором более 1 медиа, то скачивается только какое-то одно фото или видео, и текст не сохраняется
код парсера:
import os
import json
from telethon.sync import TelegramClient
from telethon.errors import SessionPasswordNeededError
from telethon.tl.types import MessageMediaPhoto, MessageMediaDocument  # Убираем все устаревшие импорты
from config import API_ID, API_HASH, PHONE_NUMBER, ADMIN_ID
from handlers.logging import log_error, log_action  # Импортируем логирование

# Загружаем данные из last_post.json
def load_last_post():
    """Загружает данные о последнем посте из файла"""
    try:
        with open('data/last_post.json', 'r', encoding='utf-8') as file:
            data = json.load(file)
            print("Загружены данные о последнем посте:", data)  # Для отладки
            return data
    except Exception as e:
        print(f"Ошибка при загрузке данных о последнем посте: {e}")
        return {"channels": {}}


# Сохраняем данные в last_post.json
def save_last_post(data):
    """Сохраняет данные в last_post.json"""
    with open('data/last_post.json', 'w', encoding='utf-8') as file:
        json.dump(data, file, ensure_ascii=False, indent=4)


async def process_message(message, client, channel_folder):
    """Обработка сообщения, извлечение текста и медиа."""
    message_data = {
        'message_id': message.id,
        'text': "Без текста",  # Начальная установка, если текст не найден
        'media': [],
        'date': message.date.isoformat()
    }

    # Попробуем извлечь текст из разных источников
    if message.text:
        message_data['text'] = message.text
    elif hasattr(message, 'raw_text') and message.raw_text:
        message_data['text'] = message.raw_text
    elif hasattr(message, 'caption') and message.caption:
        message_data['text'] = message.caption

    # Логируем текст
    log_action(ADMIN_ID, "Текст сообщения", f"Текст: {message_data['text']}")

    if not message_data['text']:
        log_action(ADMIN_ID, "Текст не найден", f"Сообщение {message.id} не содержит текста")
    else:
        log_action(ADMIN_ID, "Текст найден", f"Текст: {message_data['text']}")

    # Проверка наличия медиа
    media_folder = f"{channel_folder}/media"
    os.makedirs(media_folder, exist_ok=True)

    # Обработка нескольких медиа в одном сообщении
    if isinstance(message.media, list):  # Если медиа несколько объектов
        log_action(ADMIN_ID, "Медиа в сообщении", f"Найдено несколько медиа объектов")
        for i, media in enumerate(message.media):
            if isinstance(media, (MessageMediaPhoto, MessageMediaDocument)):
                file_path = f"{media_folder}/{message.id}_media_{i + 1}.mp4"  # Пример для видео
                result = await client.download_media(media, file_path)
                if result:
                    message_data['media'].append({'type': 'media', 'file_path': result})
                    log_action(ADMIN_ID, "Медиа сохранено", f"Файл: {result}")
    elif isinstance(message.media, (MessageMediaPhoto, MessageMediaDocument)):  # Обработка одного медиа
        log_action(ADMIN_ID, "Обработка одного медиа", "Обрабатываем одно медиа.")
        file_path = f"{media_folder}/{message.id}_media"
        result = await client.download_media(message.media, file_path)
        if result:
            message_data['media'].append({'type': 'media', 'file_path': result})
            log_action(ADMIN_ID, "Медиа сохранено", f"Файл: {result}")

    # Логируем количество медиа
    log_action(ADMIN_ID, "Количество медиа", f"Медиа в сообщении: {len(message_data['media'])}")

    # Сохраняем данные о сообщении в JSON файл
    message_json_path = f"{channel_folder}/{message.id}.json"
    with open(message_json_path, "w", encoding="utf-8") as f:
        json.dump(message_data, f, ensure_ascii=False, indent=4)

    log_action(ADMIN_ID, "Сообщение сохранено", f"Сообщение {message.id} в канале {message.peer_id}")

    return message_data


async def get_channel_messages(api_id, api_hash, phone_number, channel_links):
    """Функция для получения сообщений с канала"""
    log_action(ADMIN_ID, "Запуск парсинга каналов", f"Каналы: {channel_links}")

    client = TelegramClient('session_name', api_id, api_hash)
    await client.start(phone_number)

    # Загружаем данные о последнем сообщении
    last_post_data = load_last_post()

    for channel_link in channel_links:
        try:
            log_action(ADMIN_ID, "Получаем сообщения", f"Из канала: {channel_link}")
            channel = await client.get_entity(channel_link)
            messages = await client.get_messages(channel, limit=10)  # Получаем последние 10 сообщений

            # Получаем имя канала (используем username канала)
            channel_name = channel.username if channel.username else str(channel.id)
            channel_folder = f"parsed_content/{channel_name}"

            # Создаём папку для канала, если она не существует
            os.makedirs(channel_folder, exist_ok=True)

            # Проверка, если это первый запуск для этого канала
            if channel_link not in last_post_data['channels']:
                # Если канал новый, добавляем его в last_post_data
                last_post_data['channels'][channel_link] = {
                    'message_id': None,
                    'date': None,
                    'text': "Без текста",
                    'media': []
                }

            # Получаем последнее сообщение
            last_message = messages[0]

            # Проверяем, если последнее сообщение не совпадает с тем, что было сохранено
            if last_post_data['channels'][channel_link]['message_id'] != last_message.id:
                # Если новое сообщение, сохраняем его данные
                await process_message(last_message, client, channel_folder)

                # Обновляем данные о последнем сообщении для канала
                last_post_data['channels'][channel_link] = {
                    'message_id': last_message.id,
                    'date': last_message.date.isoformat(),
                    'text': last_message.text if last_message.text else "Без текста",
                    'media': []  # Здесь можно добавлять информацию о медиа
                }
                log_action(ADMIN_ID, "Новое сообщение", f"Сохранено новое сообщение с id: {last_message.id}")
            else:
                log_action(ADMIN_ID, "Нет новых сообщений", "Последнее сообщение не изменилось.")

        except Exception as e:
            log_error(f"Ошибка при парсинге канала {channel_link}: {e}")

    # Сохраняем обновлённые данные о каналах и их сообщениях
    save_last_post(last_post_data)

    await client.disconnect()


async def monitor_channels():
    """Функция для мониторинга каналов и парсинга новых сообщений"""
    log_action(ADMIN_ID, "Запуск мониторинга каналов", "Начало парсинга")

    # Загружаем данные из last_post.json
    last_post_data = load_last_post()

    log_action(ADMIN_ID, "Данные последнего поста", f"{last_post_data}")  # Для отладки

    if 'channels' in last_post_data:
        # Получаем ссылки каналов
        channel_links = list(last_post_data['channels'].keys())

        # Используем API ID, API HASH и номер телефона из config.py
        api_id = API_ID
        api_hash = API_HASH
        phone_number = PHONE_NUMBER

        # Запускаем парсинг сообщений
        await get_channel_messages(api_id, api_hash, phone_number, channel_links)

        log_action(ADMIN_ID, "Парсинг завершён", "Парсинг каналов завершён успешно.")
    else:
        log_action(ADMIN_ID, "Нет каналов для парсинга", "Нет каналов, указанных в last_post.json.")
  • Вопрос задан
  • 46 просмотров
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы