打算写一个导出账号内全部已归档贴纸包的脚本,被Telegram的
TG最多可以添加200个贴纸包,当超过之后最老的贴纸包会被自动归档,我TG用了几年了,一看,嗯,3000多个已归档贴纸包,就想导出一下,然后就被硬控了,具体怎么硬控我不想说了,反正循环遍历休息各种逻辑都尝试过了还是没戏,总之下面是报告。
https://core.telegram.org/method/messages.getArchivedStickers
依据官方文档,
其工作流程如下:
客户端发送
接着客户端获取第1页结果中最后一个贴纸包的ID,并将其作为下一次请求的
然而,实际情况却是:服务器仅正确响应了
以Telethon为例,使用GetArchivedStickersRequest()方法,脚本如下:
输出:
使用基于TDLib实现的Telegram X查阅已归档贴纸包页面,依然返回77个贴纸包。不仅如此,Unigram以及官方客户端都只能获取少于80个的数据。
基于以上证据,我们可以得出结论:
这不是
这是服务器端实现的bug。问题的根源在于,当处理拥有超过100个数据的账户时,服务器的后端逻辑在处理到第三页的分页请求时出现了错误。它没能正确解析
打个比方:
想象你在用某APP浏览文章,看完前2页,翻页,又出现了第1页。
那很搞笑了,我看看有什么办法可以让官方修修这个问题。
messages.getArchivedStickers()方法折磨了几个月后,我可以确信这是服务器端的问题,而不是客户端的方法定义有问题。TG最多可以添加200个贴纸包,当超过之后最老的贴纸包会被自动归档,我TG用了几年了,一看,嗯,3000多个已归档贴纸包,就想导出一下,然后就被硬控了,具体怎么硬控我不想说了,反正循环遍历休息各种逻辑都尝试过了还是没戏,总之下面是报告。
https://core.telegram.org/method/messages.getArchivedStickers
依据官方文档,
messages.getArchivedStickers()方法允许用户通过分页方式浏览其已归档的贴纸包列表,该方法接受偏移量ID offset_id 和单次获取数量限制 limit 两个参数,旨在实现标准的分页浏览机制。其工作流程如下:
客户端发送
offset_id=0,服务器返回第1页贴纸包;接着客户端获取第1页结果中最后一个贴纸包的ID,并将其作为下一次请求的
offset_id,从而获取第二页数据。如此循环,直至服务器返回空列表。然而,实际情况却是:服务器仅正确响应了
offset_id=0首次请求和第1页结果中最后一个贴纸包的ID的第二次请求。对于所有后续的、携带了有效offset_id的请求,服务器完全无视该参数,再次返回第1页的数据。这种行为使任何超过2页数据量的归档贴纸包都无法通过此API访问。以Telethon为例,使用GetArchivedStickersRequest()方法,脚本如下:
import json
import asyncio
from telethon.sync import TelegramClient
from telethon.tl.functions.messages import GetArchivedStickersRequest
API_ID = '数据删除'
API_HASH = '数据删除'
SESSION_NAME = 'account'
JSON = 'sticker.json'
async def main():
async with TelegramClient(SESSION_NAME, API_ID, API_HASH) as client:
try:
initial_request = await client(GetArchivedStickersRequest(offset_id=0, limit=1, masks=False))
total_count = initial_request.count
except:
return
seen_ids = set()
all_archived_sets = []
offset_id = 0
is_stuck = False
while len(seen_ids) < total_count:
count_before = len(seen_ids)
print(f"DEBUG: offset_id = {offset_id}")
try:
result = await client(GetArchivedStickersRequest(offset_id=offset_id, limit=100, masks=False))
except:
break
if not result.sets:
break
new_items = 0
for s in result.sets:
if s.set.id not in seen_ids:
seen_ids.add(s.set.id)
all_archived_sets.append(s.set)
new_items += 1
print(f"新增 {new_items} 个")
if new_items == 0 and len(result.sets) > 0:
print("API开始返回重复数据 终止")
is_stuck = True
break
offset_id = result.sets[-1].set.id
print(f"最终获取 {len(all_archived_sets)} / {total_count} 个贴纸包")
with open(JSON, 'w', encoding='utf-8') as f:
json.dump(
[{'id': s.id, 'access_hash': s.access_hash, 'title': s.title, 'short_name': s.short_name}
for s in all_archived_sets],
f, indent=4, ensure_ascii=False
)
if __name__ == '__main__':
asyncio.run(main())输出:
zgqinc@B850M-PLUS:/mnt/f/test/telethon$ python3 acv_sticker.py
DEBUG: offset_id = 0
新增 40 个
DEBUG: offset_id = 591378...
新增 37 个
DEBUG: offset_id = 747964...
新增 0 个
API开始返回重复数据 终止
最终获取 77 / 3410 个贴纸包使用基于TDLib实现的Telegram X查阅已归档贴纸包页面,依然返回77个贴纸包。不仅如此,Unigram以及官方客户端都只能获取少于80个的数据。
基于以上证据,我们可以得出结论:
这不是
messages.getArchivedStickers()方法定义的问题。因为该方法在前两页的请求中工作得非常完美,证明其参数设计是正确的。TDLib和Telethon都在以正确的方式使用这个方法。这是服务器端实现的bug。问题的根源在于,当处理拥有超过100个数据的账户时,服务器的后端逻辑在处理到第三页的分页请求时出现了错误。它没能正确解析
offset_id参数来定位到数据列表的相应位置,而是错误地重置或返回了初始位置的数据。打个比方:
想象你在用某APP浏览文章,看完前2页,翻页,又出现了第1页。
那很搞笑了,我看看有什么办法可以让官方修修这个问题。