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

Python3.9使用Telethon报断开连接无法发送请求错误排查

问题场景

Python 3.9环境下使用Telethon库实现批量删除频道、聊天会话功能,运行提供的代码时触发报错:

raise ConnectionError('Cannot send requests while disconnected')
ConnectionError: Cannot send requests while disconnected
报错直接触发原因
  • 客户端实例管理混乱:delete_all_dialogs和leave_all_groups两个函数各自调用auth_client()生成独立的TelegramClient实例,其中leave_all_groups内创建的客户端从未执行await client.start()建立连接,直接发起API请求就会触发未连接错误。
  • 异步执行逻辑完全错误:main函数中先通过await执行完两个业务函数,再将两个函数的None类型返回值传入asyncio.gather做并发调度,实际gather没有执行任何有效业务逻辑,还因为两个函数持有独立客户端实例导致连接状态完全不可控。
  • 裸异常捕获吞掉前置错误:delete_all_dialogs中使用无差别except: pass捕获所有异常,把客户端断连、权限不足、API调用失败等错误全部静默,导致前置流程的连接异常无法被提前感知。
代码存在的其他严重问题
  • 连接资源泄漏:两个业务函数各自创建客户端实例,既不复用已有连接,也没有在使用完成后主动关闭连接,会造成TCP连接泄漏。
  • 群组判断逻辑完全失效:leave_all_groups中写有判断条件if chat == True:,其中chat是Telegram返回的会话实体对象,永远不可能等于布尔值True,导致群组列表groups始终为空,退群逻辑根本不会触发。
  • 会话拉取不全:手动调用GetDialogsRequest仅拉取第一页最多200个会话,没有实现分页翻页逻辑,账号下会话总数超过200时,剩余会话完全不会被处理。
  • API调用参数错误:LeaveChannelRequest要求传入的channel参数为会话实体/InputPeer对象/数字ID,代码中传入username字符串,会触发参数类型错误。
  • 权限参数使用错误:delete_dialog的revoke=True参数仅对私聊双方会话生效,对群组、频道调用该参数会触发权限错误,普通用户无权撤回群组/频道内的全量历史消息。
  • 未过滤特殊会话:代码会尝试删除/退出收藏夹(Saved Messages)、Telegram官方通知等无法主动退出/删除的系统会话,直接触发API报错。
  • 事件循环写法过时:Python 3.7+版本可直接使用asyncio.run()启动协程,不需要手动获取事件循环对象调用run_until_complete。
  • 无频率限制防护:批量调用API时没有添加请求间隔,很容易触发Telegram的接口频率限制,导致账号被临时限制请求。
修复方案

修复核心思路:

  • 全局仅创建一个TelegramClient实例,统一管理连接的建立和释放
  • 直接使用Telethon内置的iter_dialogs方法自动处理会话拉取的分页逻辑,不需要手动实现底层GetDialogsRequest调用
  • 修正会话类型判断逻辑,跳过无法删除的系统特殊会话
  • 针对不同会话类型使用正确的删除/退出参数,移除无效的并发逻辑
  • 添加单会话级别的异常捕获,单个会话处理失败不中断整体流程,添加合理的请求间隔避免触发频率限制

修复后的完整可运行代码:

import asyncio
from telethon import TelegramClient

# 替换为自己账号的API凭证
API_ID = 12345
API_HASH = "0123456789abcdef0123456789abcdef"
SESSION_NAME = "main_session"

async def main():
    # 使用上下文管理器自动管理客户端连接生命周期,退出时自动断开
    async with TelegramClient(SESSION_NAME, API_ID, API_HASH) as client:
        process_count = 0
        # 内置iter_dialogs自动处理分页,拉取账号下所有会话
        async for dialog in client.iter_dialogs():
            process_count += 1
            try:
                # 跳过自己的收藏夹(Saved Messages),该会话无法删除
                if dialog.is_user and dialog.entity.id == (await client.get_me()).id:
                    print(f"{process_count} - 跳过收藏夹会话")
                    continue

                # 处理群组/频道:退出后删除会话,关闭revoke避免权限错误
                if dialog.is_group or dialog.is_channel:
                    await client.delete_dialog(dialog, revoke=False)
                    print(f"{process_count} - 已退出并删除群/频道:{dialog.name}")
                # 处理私聊会话:可根据需求选择是否开启revoke撤回自己发送的历史消息
                elif dialog.is_user:
                    await client.delete_dialog(dialog, revoke=True)
                    print(f"{process_count} - 已删除私聊会话:{dialog.name}")
                else:
                    print(f"{process_count} - 跳过未知类型会话:{dialog.name}")

                # 添加500ms请求间隔,避免触发API频率限制
                await asyncio.sleep(0.5)
            except Exception as e:
                print(f"{process_count} - 处理会话[{dialog.name}]失败:{str(e)}")
                continue

if __name__ == "__main__":
    asyncio.run(main())

内容的提问来源于stack exchange,提问作者2'71ヅ Danger

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 10:18:23