这绝对是我这辈子遇到过的最令人破防的官方服务端级别弱智 Bug。
起因是我打算用 Python 写一个脚本,导出我 TG 账号里所有已归档的贴纸包。 (科普:TG 客户端最多只能同时激活 200 个贴纸包,超过限制后,最老的贴纸包会被系统自动塞进隐形的归档库里。) 我玩 TG 这么多年了,打开底层数据一看:好家伙,我已经攒了 3000 多个已归档的贴纸包! 于是我就想着全部爬出来做个索引。
然后我就被 Telegram 官方极其恶心的 messages.getArchivedStickers() 接口给生生硬控了整整几个月!
在尝试了各种循环、延迟、休息等复杂的爬虫规避逻辑后,我依然无法获取完整列表。直到我把底层抓包数据拆开,我才敢 100% 确信:这根本不是什么第三方库的客户端方法定义写错了,这 TM 就是 Telegram 俄罗斯官方服务端写出的极其弱智的底层翻页 Bug!
🕵️♂️ 深度逆向技术报告:
依据官方这极其简陋的文档,该接口接受两个参数:偏移量 offset_id 和获取限制数量 limit。旨在实现一个极其标准的列表分页浏览机制。
其理论上的标准工作流程应该是:
- 客户端发送
offset_id=0,服务器正常返回第 1 页的贴纸包列表。 - 客户端提取第 1 页列表里最后一个贴纸包的 ID,并将其作为下一次请求的
offset_id,去请求第 2 页。 - 如此循环往复,直到服务器返回一个空列表,宣告抓取结束。
但是极其荒诞的实际情况却是:
Telegram 的后端服务器,仅仅只正确响应了 offset_id=0 的首次请求,以及第二页的请求!
对于所有后续的、哪怕你携带了极其合法的 offset_id 的第三页、第四页请求,官方服务器统统彻底无视了这个参数,直接极其弱智地再次给你返回第 1 页的重复数据!
这种极其恶劣的循环死锁行为,导致任何超过 2 页数据量 (大于100个) 的归档贴纸包,在这个宇宙中都永远无法通过此官方 API 访问到!
我不死心地用 Telethon 框架写了一套极其严谨的测试脚本:
1
# (此处省略一万字包含死锁检测和去重的 Telethon 脚本源码,结论就在下面的控制台输出里)
终端真实输出记录:
DEBUG: offset_id = 0新增 40 个DEBUG: offset_id = 591378...新增 37 个DEBUG: offset_id = 747964...新增 0 个API开始返回重复数据 终止最终获取 77 / 3410 个贴纸包
我不信邪,又去测试了基于 TDLib 底层实现的第三方神级客户端 Telegram X 里的“已归档贴纸”页面,结果它同样只能极其可怜地刷出 77 个包就到底了!不仅如此,连 Windows 上的 Unigram 以及手机上的官方原版客户端,在那个界面里都只能往下滚动出不到 80 个数据。
结论极其清晰:
这绝对不是什么接口定义问题。因为该方法在前两页的请求交互中工作得极其完美,这证明接口的参数结构设计是 100% 正确的。
问题就是:帕维尔·杜罗夫家那帮高薪雇来的后端工程师,在处理海量数据的翻页逻辑时,代码写疵了! 当处理到第三页请求时,服务端根本没去解析那个 offset_id 偏移量定位针,而是极其粗暴地让游标重置回了起点!
打个极其通俗的比方: 这就好比你极其兴奋地在看一本小说,看完前两页,翻过去第三页,结果印的又是第一页的内容。
极其搞笑!目前已经提交工单,我倒要看看这帮官方大爷什么时候能把这种弱智 Bug 给修了。