Telegram自动化脚本分享 如何利用 GetHistoryRequest 批量抓取万级频道历史消息的性能极限
面对拥有数万甚至数十万条历史消息的 Telegram 频道,直接循环调用 GetHistoryRequest 看似简单,实际却会受到单次返回数量、网络往返、FloodWait、数据落库和媒体处理等多重瓶颈影响。
本文以 Python 与 Telethon 为例,拆解批量抓取万级频道历史消息的性能边界,并给出一套兼顾速度、稳定性、可恢复性与账号安全的工程方案。
🚧 GetHistoryRequest 的真实限制
GetHistoryRequest 是 Telegram MTProto 中用于读取会话历史消息的底层请求,Telethon 的 iter_messages() 和 get_messages() 在许多场景下也会基于类似机制完成分页。
服务端不会因为客户端将 limit 设置为几千,就在一次请求中返回全部数据;实践中应按每页最多约 100 条设计分页逻辑,因此抓取 10,000 条消息通常至少需要约 100 次有效请求。
from telethon.tl.functions.messages import GetHistoryRequest
history = await client(GetHistoryRequest(
peer=channel,
offset_id=0,
offset_date=None,
add_offset=0,
limit=100,
max_id=0,
min_id=0,
hash=0
))
这里的性能上限不是单纯的“每秒请求数”,而是由接口往返延迟、数据中心连接质量、Telegram 风控节奏和本地处理能力共同决定。
此外,账号只能读取其本身有权限查看的内容;私有频道、已删除消息、受限内容以及加入频道之前不可见的历史记录,不会因为使用底层 API 而绕过权限。
⚙️ 第一步:建立稳定的分页游标
Telegram自动化脚本分享 批量抓取最关键的参数是 offset_id。首次请求将其设为 0,之后取当前批次最后一条消息的 ID 作为下一页游标,即可持续向更早的历史记录翻页。
不要假设消息 ID 连续,因为删除消息、频道迁移和服务端过滤都可能造成缺口;正确终止条件应是返回为空、达到目标数量或越过指定时间边界。
async def fetch_history(client, channel, target=10000):
offset_id = 0
collected = []
while len(collected) < target:
batch = await client(GetHistoryRequest(
peer=channel,
offset_id=offset_id,
offset_date=None,
add_offset=0,
limit=min(100, target - len(collected)),
max_id=0,
min_id=0,
hash=0
))
if not batch.messages:
break
collected.extend(batch.messages)
offset_id = batch.messages[-1].id
return collected
这段代码适合解释核心逻辑,但生产环境不应把万级消息长期堆在内存中。更稳妥的方法是按批写入数据库,同时保存频道 ID、最后游标和抓取时间。
🚀 第二步:找到吞吐量的性能极限
如果单次请求连同网络延迟平均耗时 300 毫秒,那么串行抓取 100 页的理论网络耗时约为 30 秒;若平均延迟升至 800 毫秒,总时间就可能接近 80 秒。
Telegram自动化脚本分享 因此,“万级消息几秒抓完”的宣传通常忽略了数据中心距离、账号限流、首次鉴权、实体解析和数据库写入,不能作为通用基准。
1. 复用连接与实体对象
应在任务生命周期内复用同一个 TelegramClient,并提前调用 get_input_entity() 获取目标实体,避免每一页都重新解析用户名或建立连接。
2. 将网络抓取与数据处理解耦
网络协程只负责读取和投递数据,消费者协程负责 JSON 序列化、清洗与落库。使用有容量上限的 asyncio.Queue,可以形成背压机制,防止数据库变慢时内存无限增长。
3. 不要并发分页同一频道
同一频道的下一页依赖上一页产生的游标,盲目并发会引入重复、遗漏和排序问题。真正适合并发的是不同频道之间的任务,并发度仍需根据账号状态和 FloodWait 反馈动态调整。
电报精准找群黑科技提示:
由于 Telegram 官方搜索对中文支持极差,很多优质的推广、技术和资源群组隐藏极深。如果你正在寻找相关的活跃社群,强烈推荐使用本站首页的 【TTSO - Telegram 智能搜索 Bot】。作为目前最好用的电报综合搜索导航,只需输入关键词,即可秒级触达数十万个精选 TG 中文群组、资源频道。一键直达,帮你节省 90% 的找群时间!
Telegram自动化脚本分享 🛡️ 第三步:正确处理 FloodWait 与异常恢复
Telegram 不公开固定且适用于所有账号的请求频率阈值,限制会受到账号年龄、请求类型、目标数量和历史行为影响。工程上必须捕获 FloodWaitError,并严格等待服务端给出的秒数。
import asyncio
from telethon.errors import FloodWaitError, RPCError
try:
batch = await client(GetHistoryRequest(...))
except FloodWaitError as exc:
await asyncio.sleep(exc.seconds + 1)
except RPCError as exc:
logger.exception("Telegram RPC failed: %s", exc)
Telegram自动化脚本分享 不要通过高频切换代理、多个账号轮询或无视等待时间来对抗限流,这会提高账号受限概率。合理方案是降低并发、增加随机间隔、记录检查点并允许任务续跑。
检查点至少应包含 channel_id、access_hash、offset_id、累计数量和更新时间,写入数据时则以“频道 ID + 消息 ID”建立唯一约束,从源头实现幂等去重。
📊 第四步:用指标定位真正瓶颈
性能测试不能只记录总耗时,至少要采集每页延迟、每秒消息数、重试次数、FloodWait 时长、写库耗时和峰值内存。建议先使用 1,000 条消息预热,再测试 10,000 条以上的稳定吞吐。
throughput = message_count / elapsed_seconds
request_latency = request_elapsed / page_count
retry_rate = retry_count / max(page_count, 1)
如果网络等待占比最高,应检查数据中心连接和请求节奏;如果 CPU 占用高,则通常是文本解析或序列化过重。若数据库写入最慢,应采用批量插入、事务提交和合适索引,而不是继续增加 Telegram 请求并发。
还要区分“消息元数据抓取”与“媒体下载”:图片、视频和文档需要额外请求及带宽,整体耗时可能从分钟上升到数小时,不能与纯文本历史读取使用同一性能指标。
✅ 推荐的生产级抓取策略
对于单个万级频道,优先采用每页 100 条、顺序分页、批量落库、游标持久化的方案。任务异常退出后,从最近一次成功提交的游标恢复,而不是重新扫描全部消息。
对于多个频道,可设置较小的全局并发池,并根据实际 FloodWait 自动降速。长期增量同步则保存最新消息 ID,后续只读取新增区间,避免反复消耗接口配额和本地资源。
最后,采集行为应遵守 Telegram 服务条款、目标频道规则及适用的数据保护法规。公开可见不等于可以无限复制、再分发或处理个人信息,业务上线前应明确数据用途、保存期限和删除机制。
❓ 常见问题解答(FAQ)
GetHistoryRequest 一次最多能抓多少条消息?
客户端应按每次最多约 100 条设计,实际返回数量可能因权限、消息过滤和历史末尾而更少。抓取万级历史必须通过 offset_id 分页完成。
为什么不直接使用 iter_messages?
iter_messages() 封装了分页和部分等待逻辑,更适合常规业务;直接调用 GetHistoryRequest 则便于控制游标、记录单页指标和构建自定义恢复机制。
并发越高,抓取速度就越快吗?
不是。同一频道的分页具有顺序依赖,过高并发还会增加重复数据、FloodWait 和账号限制风险,最佳并发值必须通过受控压测确定。
如何避免中断后重复抓取?
Telegram自动化脚本分享 每完成一批数据就保存游标,并以频道 ID 和消息 ID 建立数据库唯一键。恢复任务时读取最后检查点,即可实现断点续传与幂等写入。
抓取一万条消息需要多长时间?
纯消息元数据通常需要约 100 次分页请求,耗时取决于网络延迟、限流等待和落库速度,无法给出适用于所有账号的固定值。应在真实运行环境中记录指标,并以稳定、无 FloodWait 的持续吞吐作为优化目标。

