讲师中心 微信公众号
AI工具推荐 视频效率加速

Pyrogram 中正确处理和转发媒体组消息的教程

酷婷君_7711

酷婷君_7711

发布时间:2025-11-24 13:35:01

|

1033人浏览过

|

来源于php中文网

原创

Pyrogram 中正确处理和转发媒体组消息的教程

本教程详细讲解如何在 pyrogram 中有效处理和转发 telegram 媒体组消息,避免重复发送问题。文章阐述了 telegram 媒体组的特性,并提供了一种基于消息流识别和 `copy_media_group` 方法的解决方案,确保用户机器人能够准确无误地复制和转发完整的媒体组。

引言:理解 Pyrogram 中的媒体组消息

在 Pyrogram 中开发用户机器人时,处理 Telegram 的媒体组(如相册或文件集合)是一个常见的挑战。当机器人接收到一个媒体组时,Pyrogram 会将组内的每个媒体项作为独立的消息触发 on_message 事件。这导致的一个常见问题是,如果直接尝试转发每个触发的消息,最终会发送多份相同的媒体项,而不是一个完整的媒体组。

Telegram 将媒体组视为一种视觉上的分组机制,而非一个单一的容器对象。这意味着,虽然用户界面上它们显示为一个整体,但在底层 API 层面,它们仍然是多条独立的消息,只是通过 media_group_id 字段关联起来。因此,解决问题的关键在于正确识别并等待媒体组中的所有消息都到达,然后一次性转发整个组。

解决方案核心:识别与批量转发

要正确处理媒体组并避免重复转发,核心思路是:

  1. 识别媒体组消息: 通过检查 message.media_group_id 属性来判断当前消息是否属于一个媒体组。
  2. 获取完整媒体组: 使用 app.get_media_group() 方法获取与当前 media_group_id 相关联的所有消息。
  3. 确定组内最后一条消息: 在 on_message 事件多次触发时,只有当处理到媒体组的最后一条消息时,才执行转发操作。
  4. 批量转发: 使用 app.copy_media_group() 方法一次性转发整个媒体组。

实现步骤与示例代码

下面是一个 Pyrogram 用户机器人示例,演示了如何根据上述核心思路来处理和转发媒体组。

首先,确保你的环境中安装了 pyrogram 和 pyyaml:

testing-python
testing-python

使用pytest编写和评估有效的Python测试。适用于编写测试、审查测试代码、调试测试失败或提高测试覆盖率。

下载
pip install pyrogram pyyaml

然后,创建一个 config.yaml 文件来存储你的 API 凭据和目标频道 ID:

id: YOUR_API_ID
hash: YOUR_API_HASH
channels:
  - SOURCE_CHAT_ID_1 # 来源聊天ID,可以是数字或用户名
  - SOURCE_CHAT_ID_2
my_channel: TARGET_CHANNEL_ID # 目标频道ID

请将 YOUR_API_ID、YOUR_API_HASH、SOURCE_CHAT_ID_X 和 TARGET_CHANNEL_ID 替换为你的实际值。SOURCE_CHAT_ID_X 可以是单个 ID 或一个列表。

接下来是 Python 代码实现:

import pyrogram
from pyrogram import filters
import yaml
import asyncio

# 加载配置
try:
    with open("config.yaml", "r") as f:
        config = yaml.safe_load(f)
except FileNotFoundError:
    print("Error: config.yaml not found. Please create one with your API ID, API HASH, and channel IDs.")
    exit()

api_id = config["id"]
api_hash = config["hash"]
source_channels = config["channels"]
target_channel = config["my_channel"]

# 初始化 Pyrogram 客户端
app = pyrogram.Client(
    'my_account',
    api_id=api_id,
    api_hash=api_hash
)

# 用于存储已处理的媒体组ID,避免重复处理
processed_media_groups = set()

@app.on_message(filters.chat(source_channels))
async def copy_to_my_channel(client, message):
    # 如果消息没有 media_group_id,则它是单条消息
    if message.media_group_id is None:
        print(f"Received single message (ID: {message.id}). Copying...")
        await client.copy_message(
            from_chat_id=message.chat.id,
            chat_id=target_channel,
            message_id=message.id
        )
        print(f"Single message (ID: {message.id}) copied.")
    else:
        # 这是一个媒体组消息
        media_group_id = message.media_group_id

        # 检查是否已经处理过这个媒体组,如果是,则跳过
        if media_group_id in processed_media_groups:
            # print(f"Media group {media_group_id} already processed. Skipping message {message.id}.")
            return

        print(f"Received message (ID: {message.id}) belonging to media group {media_group_id}.")

        # 获取媒体组中的所有消息
        # 注意:get_media_group 可能会在媒体组消息尚未完全到达时被调用,
        # 导致返回不完整的列表。可以添加一个短暂停顿或重试机制来提高健壮性。
        await asyncio.sleep(0.5) # 给Telegram一点时间来聚合所有消息

        full_media_group = await client.get_media_group(
            chat_id=message.chat.id,
            message_id=message.id # 任何属于该媒体组的消息ID都可以
        )

        # 查找当前消息在完整媒体组中的索引
        current_message_index = -1
        for i, msg in enumerate(full_media_group):
            if msg.id == message.id:
                current_message_index = i
                break

        # 只有当当前消息是媒体组中的最后一条消息时,才执行转发
        # 这里的判断逻辑需要更严谨,因为消息到达的顺序不总是线性的。
        # 最可靠的方法是等待一段时间,然后一次性处理。
        # 但为了演示,我们先使用这种基于“最后一条消息”的简化逻辑。
        # 更好的做法是收集所有消息ID,然后在检测到“完成”时发送。
        # 对于Pyrogram的get_media_group,它通常会返回完整的组,
        # 所以我们只需确保只执行一次copy_media_group。

        # 标记此媒体组为已处理,防止后续触发重复发送
        processed_media_groups.add(media_group_id)

        # 提取所有消息的ID
        message_ids_to_copy = [msg.id for msg in full_media_group]

        print(f"Detected complete media group {media_group_id} with IDs: {message_ids_to_copy}. Copying...")

        # 使用 copy_media_group 转发整个媒体组
        await client.copy_media_group(
            chat_id=target_channel,
            from_chat_id=message.chat.id,
            message_ids=message_ids_to_copy
        )
        print(f"Media group {media_group_id} published to {target_channel}.")

# 运行客户端
if __name__ == '__main__':
    print("Bot started. Listening for messages...")
    app.run()

代码解析与注意事项

  1. config.yaml 配置: 将敏感信息(如 API ID 和 Hash)和可变配置(如频道 ID)外部化到 YAML 文件中,方便管理和部署。
  2. @app.on_message(filters.chat(source_channels)): 这是一个消息处理器,它会监听来自 config.yaml 中指定 source_channels 的所有消息。
  3. 单条消息处理:
    • if message.media_group_id is None::如果消息没有 media_group_id,则它是一个独立的消息(如纯文本、单个图片等)。
    • await client.copy_message(...):直接使用 copy_message 方法转发此单条消息。
  4. 媒体组消息处理:
    • else: 块处理带有 media_group_id 的消息。
    • processed_media_groups = set():引入一个集合来存储已处理的 media_group_id。这是防止重复转发的关键机制。当 on_message 对同一个媒体组中的多条消息触发时,只有第一次会进入实际处理逻辑。
    • await asyncio.sleep(0.5):这是一个经验性的等待,因为 Telegram 在发送媒体组时,并非所有消息都会同时到达。短暂的延迟可以增加 get_media_group 返回完整列表的概率。对于生产环境,可能需要更复杂的重试或消息收集机制。
    • full_media_group = await client.get_media_group(chat_id=message.chat.id, message_id=message.id):这是获取整个媒体组的关键方法。message_id 可以是媒体组中任意一条消息的 ID。Pyrogram 会使用这个 ID 去查询该媒体组中的所有相关消息。
    • processed_media_groups.add(media_group_id):一旦我们决定处理一个媒体组(通常是第一次遇到其任何一条消息时),就将其 media_group_id 添加到 processed_media_groups 集合中,这样后续属于同一媒体组的消息触发 on_message 时,就会被 if media_group_id in processed_media_groups: 语句跳过,避免重复处理。
    • message_ids_to_copy = [msg.id for msg in full_media_group]:从 full_media_group 中提取所有消息的 ID,以备批量转发。
    • await client.copy_media_group(chat_id=target_channel, from_chat_id=message.chat.id, message_ids=message_ids_to_copy):这是 Pyrogram 提供的专门用于转发整个媒体组的方法。它接收一个消息 ID 列表,并将其作为一个整体发送到目标聊天。

总结

通过上述方法,我们能够有效地在 Pyrogram 中处理 Telegram 媒体组消息。关键在于理解 Telegram 媒体组的底层机制,利用 message.media_group_id 进行识别,并通过 client.get_media_group() 获取完整组信息,最终使用 client.copy_media_group() 进行批量转发。结合 processed_media_groups 集合来避免重复处理,可以确保机器人行为的准确性和效率。这个模式不仅适用于转发,也适用于任何需要对整个媒体组进行统一操作的场景。

热门AI工具

更多
二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

Seko
Seko Hot

一款AI视频创作工具,主要用于商汤科技推出的创编一体的AI短视频创作Agent,适合需要提升相关任务效率的用户。

LibLibAI
LibLibAI Hot

一款AI视频创作工具,主要用于国内领先的AI创意平台,以海量模型、低门槛操作与“创作-分享-商业化”生态,让小白与专业创作者都能高效实现图文乃至视频创意表达,适合需要提升相关任务效率的用户。

Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

讯飞智作

讯飞智作是一款AI视频创作工具,AI文本配音工具,数字人课程、营销视频制作。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

相关专题

更多
FrankenPHP集成Laravel详细教程
FrankenPHP集成Laravel详细教程

本专题提供FrankenPHP集成Laravel的详细配置指南,全面解析运行原理、开发环境搭建、Caddyfile配置、Octane工作模式、数据库连接、队列任务、定时任务和生产环境优化,解决部署过程中常见的报错与兼容性问题。

0

2026.10.08

LLVM自定义Pass怎么写
LLVM自定义Pass怎么写

本专题聚焦LLVM自定义Pass开发,整理Pass类结构、run()方法、PreservedAnalyses、CMake构建、插件注册、-load-pass-plugin加载和测试用例编写流程。

120

2026.09.30

LLVM RISC-V参数配置教程
LLVM RISC-V参数配置教程

本专题介绍LLVM对RISC-V基础ISA和扩展的支持方式,涵盖RV32、RV64、标准扩展、实验性扩展、厂商扩展、-menable-experimental-extensions和版本差异。

100

2026.09.30

LLVM IR中间表示入门指南
LLVM IR中间表示入门指南

本专题整理LLVM IR的核心概念,包括中间表示作用、模块结构、函数、基本块、SSA形式、类型系统和常见语法,帮助新手理解LLVM编译流程中的关键层。

80

2026.09.30

PDF转图片方法
PDF转图片方法

需要把 PDF 页面用于上传、预览、分享或图片归档时,PDF 转图片方法专题整理 JPG/PNG 格式选择、逐页导出、清晰度设置、批量下载和结果检查等流程,帮助用户稳定完成 PDF 图片化处理。

80

2026.09.30

PixTV AI视频生成与无限画布创作
PixTV AI视频生成与无限画布创作

PixTV专题整理AI视频与视觉内容创作相关功能使用教程,涵盖AI生图、视频生成、无限画布、多模型创作、素材管理、声音音乐及视频剪辑等功能,帮助用户快速掌握PixTV从创意到成片的完整制作方法。

100

2026.09.29

Buffalo框架数据库开发全教程
Buffalo框架数据库开发全教程

本专题围绕Buffalo框架数据库开发,讲解database.yml多环境配置、soda与fizz迁移生成回滚、模型结构体标签、增删改查与条件查询、一对多与多对多关联、数据校验、回调钩子、事务处理及原生SQL执行能力。

300

2026.09.23

Buffalo框架路由与请求处理实操指南
Buffalo框架路由与请求处理实操指南

本专题讲解Buffalo框架路由与请求处理机制,涵盖路由注册与分组、资源路由、Handler编写规范、Context上下文方法、参数绑定、中间件编写挂载、Session与Cookie读写、Flash消息及错误页面定制方法。

180

2026.09.23

Buffalo框架零基础入门教程
Buffalo框架零基础入门教程

本专题整理Buffalo框架入门内容,涵盖Go环境准备、buffalo CLI安装、新项目生成、目录结构说明、dev热加载启动、数据库连接配置与常见报错排查,帮助新手按约定优于配置的思路跑通第一个Buffalo框架应用。

140

2026.09.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn