tk:指令虚拟机的另一个样本
谷歌翻译 translate_a/t 接口的 tk 参数,和百度翻译 sign 用的是同一套设计思想——指令串驱动的位运算器。如果你已经搞懂了百度那套,谷歌这个十分钟就能拿下;反过来也一样。两家"撞设计"不是巧合,这套结构本来就是前端混淆的经典范式。
TKK 种子
页面里写着 TKK='444385.4274552210' 之类的值,定期更新。它是 tk 计算的初始状态,工程上启动时从 translate.google.com 页面提取,不写死。
算法完整实现
def xr(a, ops):
# 指令执行器:每3字符一条指令 [累加/异或][左移/右移][位数]
for i in range(0, len(ops) - 2, 3):
d = ops[i + 2]
d = ord(d) - 87 if d >= 'a' else int(d)
d = (a >> d) if ops[i + 1] == '+' else (a << d)
a = ((a + d) & 0xFFFFFFFF) if ops[i] == '+' else (a ^ d)
return a
def utf16_codes(text):
# 与百度翻译同款:emoji 代理对必须拆成两个 UTF-16 码元
codes = []
for ch in text:
cp = ord(ch)
if cp > 0xFFFF:
codes.extend([0xD800 + ((cp - 0x10000) >> 10),
0xDC00 + ((cp - 0x10000) & 0x3FF)])
else:
codes.append(cp)
return codes
def google_tk(text, tkk):
seed1, seed2 = (int(float(x)) for x in tkk.split('.'))
a = seed1
for code in utf16_codes(text):
a += code
a = xr(a, '+-a^+6')
a = xr(a, '+-3^+b+-f')
a ^= seed2
if a < 0:
a = (a & 0x7FFFFFFF) + 0x80000000
a %= 1000000
return f"{a}.{a ^ seed1}"Python 移植的核心坑:32 位语义
JS 的位运算全程 32 位有符号整数语义,Python 整数无限精度——这是移植此类算法时结果发散的唯一原因。三条纪律:
- 每次加法后
& 0xFFFFFFFF - 左移结果也要
& 0xFFFFFFFF(Python 左移不会溢出,JS 会) - 最终判断负数时按 JS 的补码规则处理(上面代码里的
if a < 0分支)
写完用浏览器的中间结果对拍:同一个文本,Console 里单步执行看每轮 a 的值,和 Python 逐轮对比,第一轮不一致就能定位到哪条指令翻车了。
请求示例
params = {
'client': 't', 'sl': 'zh-CN', 'tl': 'en',
'hl': 'zh-CN', 'dt': ['at', 'bd', 'ex', 'ld', 'md', 'qca', 'rw', 'rm', 'ss', 't'],
'ie': 'UTF-8', 'oe': 'UTF-8', 'q': text, 'tk': google_tk(text, tkk),
}
resp = session.get('https://translate.googleapis.com/translate_a/t', params=params)进阶:batchexecute 路线
translate_a/t 是公开端点,限流较严。谷歌翻译网页版实际走的是 translate.google.com/_/TranslateWebserverUi/data/batchexecute——这是谷歌通用的 RPC 框架端点:
- 不需要 tk,但需要页面里的
f.sid(会话 id)和bl(构建版本)参数 - 请求体是
f.req=开头的 RPC 编码格式,响应是)]}'前缀的 json 数组 - 限流阈值比 translate_a/t 宽松,且翻译质量参数更全
batchexecute 的协议格式是谷歌系通用技能(Google 全家桶都用它),值得单独研究一次,终身受用。
总结
- tk 算法 = TKK 种子 + 指令虚拟机,和百度 sign 同宗
- Python 移植的全部坑都在 32 位整数语义,对拍是唯一裁判
- translate_a/t 简单但限流严,batchexecute 复杂但宽松
- emoji 代理对拆分,和百度翻译共用同一个 utf16_codes 函数