You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Telethon修改消息内容及按钮后转发至其他频道时遭遇TypeError: cannot pickle 'sqlite3.Connection' object错误

解决deepcopy时的TypeError: cannot pickle 'sqlite3.Connection'对象问题

这个错误的根源很明确:你用copy.deepcopy复制event.message.buttons的时候,按钮对象内部间接引用了sqlite3.Connection实例——数据库连接这类对象是没法被序列化(pickle)的,而deepcopy在处理复杂嵌套对象时会依赖pickle机制,所以直接触发了这个报错。

你的代码里没必要直接复制整个按钮结构,反而应该重新创建按钮对象来修改内容,这样就能避开那些不能被复制的内部关联数据。下面是修改后的完整代码,我会标注关键改动点:

@client.on(events.NewMessage(chats=[channelId]))
async def handler(event):
    channels = get_channels()
    replacements = get_replacements()
    # 保存原始文本和按钮的引用,不做deepcopy
    original_msg_text = event.message.text
    original_buttons = event.message.buttons

    for channel in channels:
        replacements_api = get_replacement(channel['channel_id'], replacements)
        # 每次处理新频道都从原始文本开始替换,避免跨频道污染
        message_text = original_msg_text
        message_buttons = []

        # 先处理文本替换
        for rep_api in replacements_api:
            message_text = message_text.replace(rep_api['word'], rep_api['word_replacement'])

        # 再处理按钮替换:遍历原始按钮,逐个创建新按钮
        if original_buttons:
            for button_row in original_buttons:
                new_row = []
                for btn in button_row:
                    # 提取原始按钮的文本和URL
                    btn_text = btn.button.text
                    btn_url = btn.button.url
                    # 应用替换规则
                    new_text = btn_text
                    new_url = btn_url
                    for rep_api in replacements_api:
                        new_text = new_text.replace(rep_api['word'], rep_api['word_replacement'])
                        new_url = new_url.replace(rep_api['word'], rep_api['word_replacement'])
                    # 创建全新的按钮对象(这里以Telethon的KeyboardButtonUrl为例,根据你的库调整)
                    from telethon.tl.types import KeyboardButtonUrl
                    new_btn = KeyboardButtonUrl(text=new_text, url=new_url)
                    new_row.append(new_btn)
                message_buttons.append(new_row)

        # 直接发送处理后的内容,不要修改原始event.message
        await client.send_message(
            channel['channel_id'],
            message=message_text,
            buttons=message_buttons if message_buttons else None
        )

关键改动说明:

  1. 移除deepcopy操作:不再复制整个按钮结构,而是遍历原始按钮,手动创建新的按钮实例,彻底避开了内部的数据库连接对象。
  2. 不修改原始事件对象:原来的代码会修改event.message.text,这可能会影响后续的事件处理;现在直接传递处理后的文本和按钮给send_message,更安全。
  3. 分离文本和按钮的替换逻辑:让代码结构更清晰,也方便后续维护。

额外注意:

如果你的按钮不是链接类型(比如回调按钮),需要对应调整创建新按钮的代码。比如如果是KeyboardButtonCallback,就替换成创建该类型的实例,修改对应的字段(比如text和data)即可。

内容的提问来源于stack exchange,提问作者Mamed

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.27 20:57:40