简介百度翻译接口完整代码示例面向需要在应用或网站中集成多语言翻译功能的开发者尤其适合刚接触API调用、身份验证及HTTP请求流程的初中级程序员用于快速解决从零接入百度翻译API的落地问题。压缩包内共2个文件分别为Python脚本与JavaScript文件覆盖两种主流技术栈下的调用方式整体仅5KB轻量易读便于直接修改复用也适合作为代码阅读练习。已有640人学习浏览资源清晰展示了请求URL的构建、请求头设置、参数URL编码、JSON响应解析以及常见错误处理等关键环节可作为理解API交互全流程的入门参考。代码在2023年8月前有效能帮助读者快速完成翻译功能从零到一的落地实践并在此基础上进一步扩展缓存策略、批量翻译与异步处理等优化思路。1. 百度翻译接口完整代码先从签名算法说起翻译接口的门槛从来不在 HTTP 请求而在签名。我最早接百度翻译开放平台时照着网上的旧教程抄代码结果第一条请求就撞上 52003——认证失败。后来才发现2020 年之后接入方式改成了 token 鉴权老代码里的「appid 密钥 拼接字符串 MD5」还停留在上一代标准。这套接口的真实价值在于一次搞定正确的鉴权流程、拿到可直接改用的完整代码并且把长文本分批、错误码排查这些后端才踩的坑提前排掉。适合要在软件/插件里集成多语言翻译、又不想反复调试签名逻辑的开发者。本文给出 Python 与 JavaScript 两套可运行实现按步骤替换参数即可上线。2. 调用前必须吃透的参数体系appid、密钥、salt 和签名2.1 新版鉴权流程先换 token再做签名百度翻译开放平台从 2020 年 10 月起标准版接口全面切换为 token 鉴权。旧版的「MD5 拼接签名」并没有被废弃而是被包了一层——你得先用 appid 和密钥换一个 24 小时有效的 token再用这个 token 去替换请求中的 secret 字段。这张表的参数含义务必记清楚参数说明是否必填appid创建应用时分配的 ID形如 2025010100123456是key创建应用时的密钥明文仅用于换取 token是换取 token 时token换取到的临时凭证24 小时有效是请求翻译时salt随机整数防重放每次请求重新生成是sign签名串具体算法见下文 2.2是q待翻译文本UTF-8 编码是from / to源语言 / 目标语言代码如 zh、en、auto是换取 token 的接口是https://api.fanyi.baidu.com/api/trans/v3/apitrans/token请求方式为 GET需要带上grant_typeclient_credentials、appid、key三个参数。响应是一个 JSON结构如下{ access_token: 1234567890abcdef, expires_in: 86400 }请求翻译时把access_token当作密钥去生成签名。换句话说旧版拼接是「appid q salt key」新版是「appid q salt token」。很多老教程只改了请求地址没改签名拼接所以永远报 52003。2.2 签名算法MD5 拼接顺序一个字符都不能错如果你只是想在插件里快速跑通不要自己实现签名——直接在服务端放一份现成代码改参数。但理解算法仍然重要因为调试时你得能判断是签名错还是网络错。签名原文的拼接规则是sign MD5(appid q salt token)四个字段按顺序直接拼接中间没有分隔符。q 必须和实际请求体里传的完全一致包括大小写、空格、换行符。常见翻车点请求时用了encodeURIComponent(q)签名时用了原始字符串。MD5 之后转小写十六进制字符串。每一步的中间结果可以打印出来和官方调试工具比对。我一般会建议先写死一个 salt 值比如 123456这样签名结果可复现方便排查。线上再改成随机数。2.3 开发前准备申请密钥与测试配额到翻译开放平台控制台创建应用时需要选择「标准版」还是「尊享版」。标准版免费额度是单次请求最长 6000 字符每月 100 万字符尊享版计费。个人插件开发选标准版完全够用。创建应用后页面会给出一个 appid 和一个密钥密钥只显示一次务必复制到安全的地方。常见操作失误是把密钥写死在插件包里导致打包发布后密钥泄露被他人盗用配额。正确做法是插件端只保留 appid密钥和 token 换发放在你自己的服务端中转。3. 完整代码实现Python 版与脚本插件版各来一份3.1 Python 版一次性给你可直接改用的完整请求函数我用 requests 库写了一个最小可用实现复制后替换三个常量即可跑通# -*- coding: utf-8 -*- import hashlib import json import random import time import requests APPID 你的appid TOKEN 你的token # 先用 curl 换到再填进来 def translate_text(q, from_langauto, to_langzh): # 1. 生成 salt salt str(random.randint(32768, 65536)) # 2. 计算签名appid q salt token 直接拼接 sign_str APPID q salt TOKEN sign hashlib.md5(sign_str.encode(utf-8)).hexdigest() # 3. 构造请求参数 payload { q: q, from: from_lang, to: to_lang, appid: APPID, salt: salt, sign: sign, token: TOKEN, } # 4. 发起 POST 请求 url https://api.fanyi.baidu.com/api/trans/v3/apitrans/text resp requests.post(url, datapayload, timeout5) result resp.json() # 5. 解析结果 if trans_result in result: dst result[trans_result][0][dst] return dst else: raise RuntimeError(f翻译失败: {result})逻辑说明第 2 步的签名拼接必须用原始字符串 q不能用 URL 编码后的值这是最容易出错的地方。第 4 步用的是data参数而非json参数因为接口要求application/x-www-form-urlencoded格式。第 5 步只取了第一个翻译结果生产环境建议循环取出所有段落。参数说明from_lang和to_lang支持语言代码。auto表示自动识别源语言翻译成繁体中文用cht不是zh-tw日文是jp不是ja。这个简写体系是老用户最容易踩的命名坑。调用方式print(translate_text(Hello, world., auto, zh)) # 输出你好世界。3.2 JavaScript 版插件脚本里怎么安全地携带签名如果你是在浏览器插件或本地脚本里调用复用同一个签名逻辑即可。注意MD5 需要引库生产环境建议用crypto-js或服务端中转。const crypto require(crypto); function translate(q, fromLang auto, toLang zh) { const appid 你的appid; const token 你的token; const salt Math.floor(Math.random() * 10000 1000).toString(); // 用 Node.js 自带 crypto 计算 MD5 const sign crypto .createHash(md5) .update(appid q salt token) .digest(hex); const params new URLSearchParams(); params.append(q, q); params.append(from, fromLang); params.append(to, toLang); params.append(appid, appid); params.append(salt, salt); params.append(sign, sign); params.append(token, token); return fetch(https://api.fanyi.baidu.com/api/trans/v3/apitrans/text, { method: POST, headers: { Content-Type: application/x-www-form-urlencoded }, body: params.toString(), }) .then((res) res.json()) .then((data) { if (data.trans_result) { return data.trans_result.map((item) item.dst).join(\n); } throw new Error(JSON.stringify(data)); }); }这段代码和 Python 版逻辑完全对称核心差异只在 URLSearchParams 构造请求体。map那一步把所有分段结果合并成多行字符串适合插件里直接渲染到弹窗。如果你的插件环境是浏览器而非 Nodecrypto 库不可用需要引入crypto-js或者干脆把签名计算放到服务端前端只拿结果。3.3 服务端中转防止 token 泄露的标准做法把 token 直接写在前端代码里等于把钥匙交给每个用户。标准做法是在自己的后端加一个代理接口# 先手动换取 token 保存到环境变量 curl https://api.fanyi.baidu.com/api/trans/v3/apitrans/token?grant_typeclient_credentialsappid你的appidkey你的key # 输出中的 access_token 存入环境变量 BAIDU_TOKEN后端接口每收到一次翻译请求从环境变量读 token签名后转发给百度翻译。这样一来插件端只暴露你自己的服务地址token 永远不出站。代价是多一跳网络延迟但换来的是配额安全这笔账值得。4. 响应解析、错误码与长文本分批策略4.1 响应 JSON 结构主段与逐句翻译的关系接口响应格式是稳定的但新手经常把trans_result和result搞混。正常响应长这样{ from: en, to: zh, trans_result: [ { src: Hello world., dst: 你好世界。 }, { src: How are you?, dst: 你好吗 } ] }如果请求时 q 传了多段文本用换行符\n分隔返回的trans_result是一个数组。数组下标与输入的段落顺序一一对应。如果你的原始文本没有换行只会有数组里一个元素。解析时注意两点一是不要用浮点 JSON 解析百度翻译偶尔会返回非标准 Unihan 字符二是src字段可能为空表示自动检测语种失败。更稳妥的解析策略是只取dst不依赖src。4.2 错误码速查表52003 与 54004 的区别以下是高频错误码的排查路径我根据实际调用经验整理错误码含义常见原因解决方案52001请求超时网络波动或 q 过长缩短文本设置 5 秒超时重试一次52003认证失败签名错误或 token 失效检查签名拼接顺序重新换 token54003请求频率受限并发过高或单 QPS 超标加延时队列控制 1 QPS58001语言方向不支持from和to组合无效核对语言代码表注意jp不是ja54004余额不足免费额度耗尽或未开通计费控制台查额度切换付费或降级排查顺序我一般这样走先看错误码如果 52003先打印签名原文确认q没被 URL 编码然后确认 token 是否超过 24 小时如果这两个都没问题再看时间戳是否和服务器差距过大。注意错误码 52003 和 54003 只有一字之差前者是签名错后者是频率受限。很多老开发者遇到 54003 习惯性去检查签名结果方向完全错了。4.3 长文本分批6000 字符上限的拆法标准版单次请求最大 6000 字符这是 ASCII 字符数还是 UTF-8 字节数答案是字符数。一个中文占一个字符一个 emoji 可能占两个。写了个粗暴但实用的切分函数def split_text(text, max_len5000): 按最大长度切分优先断在句子边界 if len(text) max_len: return [text] chunks [] cursor 0 while cursor len(text): end min(cursor max_len, len(text)) # 往回找最近的句号或换行 last_period text.rfind(。, cursor, end) last_newline text.rfind(\n, cursor, end) break_pos max(last_period, last_newline) if break_pos cursor max_len // 2: # 至少切掉一半才算有效边界 end break_pos 1 chunks.append(text[cursor:end]) cursor end return chunks切分逻辑说明max_len5000留 1000 字符余量避免响应拼接后超过接口隐式限制。rfind从后往前找.与换行尽量不砍断语义单元。如果找不到自然边界直接硬切到max_len保证程序不死循环。分批之后每个 chunk 单独调用翻译接口最后按顺序拼接。这里有个隐蔽问题不同 chunk 翻译出的结果可能存在术语不一致。要处理这个问题得用第 6 章的术语表方案。5. 避坑手册签名失败、限流、乱码的五个真实翻车现场5.1 现象52003 认证失败但 appid 和密钥明明是对的原因签名用的 token 是旧版已经过期。token 有效期 24 小时你在上午换的 token晚上就会失效。更隐蔽的是如果你用 curl 手动换 token 测试然后把 token 复制到了代码里代码跑了一天后必然挂。解决换 token 的流程单独封装成函数每次启动时检查本地缓存文件的时间戳超过 20 小时自动刷新。不要手动复制 token 字符串。5.2 现象翻译出来的结果是乱码英文变成中文再传回去又变英文原因请求参数q在签名时是 UTF-8但 POST 时被某些语言框架自动做了 URL 编码解码。Python 的requests.post(datapayload)会自动编码不会出问题但如果是自己构造的 HTTP 请求容易漏掉Content-Type头导致服务端按 ISO-8859-1 解码。解决构造data前显式把字符串编码为 UTF-8响应解码统一用resp.content.decode(utf-8)不要用resp.text隐式解码。排查时打印返回体的原始字节看\\u转义是否符合预期。5.3 现象长文本翻译经常漏段落或者最后一段消失原因分块逻辑里cursor递增时如果break_pos恰好在切分点的下一行end break_pos 1会把换行符吞进去导致下一 chunk 拼接后多出半个空行或缺失字符。解决切分函数把换行符当作边界的一部分保留下来分块之间用空字符串分隔而不是尝试精细化切割。翻译结果拼接时用\n.join([c.strip() for c in chunks])过滤多余空白。5.4 现象调用频率一高就返回 54003并发请求全部失败原因免费版 QPS 限制是 1也就是每秒最多一个请求。插件批量翻译时并发发起了多个请求瞬间超限。返回的频率限制不是每个请求独立的而是滚动窗口统计。解决加一个简单的单机限流队列import time class RateLimiter: def __init__(self, qps1): self.qps qps self.last 0.0 def wait(self): now time.time() gap now - self.last if gap 1.0 / self.qps: time.sleep(1.0 / self.qps - gap) self.last time.time()用法是在每次调用translate_text之前执行limiter.wait()。如果并发量很大建议挪到服务端做全局限流配合队列逐条处理。5.5 现象部分生僻字翻译结果与网站不一致原因接口的语种识别倾向不同。网站版会先识别from再匹配专业词库API 版默认走通用模型。比如医疗术语、法律条款这类专业文本API 翻译结果质量明显低于网页端。解决不要依赖自动识别。明确指定from为en或具体语种不要填auto。如果要提升术语准确率进入第 6 章的术语表方案。6. 进阶技巧自定义术语表与接口状态自检这一章讲两个真正提升使用体验的习惯一个是术语表一个是上线前的自检用例。先说话拔术表。百度翻译开放平台支持在控制台为应用添加自定义术语但很多人不知道这个功能对 API 请求同样生效。设置方式是在控制台打开你的应用进入「术语表」页签添加「原文→译文」的固定映射例如browser - 浏览器默认译法浏览器 函数 - function默认译法功能配置生效时间约 5 分钟。此后 API 请求中如果命中了术语会优先返回你在术语表里的定义而不是模型默认结果。术语表同一语言方向最多 500 条对垂直领域的软件/插件翻译这比任何 prompt 调优都可靠。如果你在做一个专业工具强烈建议把核心 UI 文案的常见误译全部录入术语表让每次翻译的结果稳定。第二条习惯是写一个接口自检脚本把调试期翻过的车固化成用例。我在每次部署前都会跑一遍下面的检查# 1. 基础翻译 curl 接口地址 --data qhellofromentozhappidxxxsalt123signxxxtokenxxx # 2. 超长文本 5000 字符确认不报 52001 # 3. 特殊字符引号、换行符、emoji确认签名一致 # 4. 连续请求 3 次确认不触发 54003 # 5. 请求一个不存在的语言方向确认返回 58001 而不是 52003特别说一下第 3 条。我踩过最深的一个坑是待翻译文本里包含英文字符串长引号时签名阶段用原始字符串但 POST 阶段被requests自动做了urlencode导致服务器拿到的q和签名里的q不一致。解决办法是在签名前先做一次urllib.parse.quote(q, safe)保证签名和传输完全同一个编码状态。从那以后我每次接翻译接口都会在测试用例里加入特殊字符组合先把边界跑完再谈上线。顺带提一句调试技巧在代码里加一个环境变量DEBUG_SIGN1开启后打印签名原文和 MD5 结果。上线时关掉。这比逐行断点快得多——签名这类问题肉眼比对长度和字符就能定位。希望这些踩坑记录帮你节约一个下午的调试时间。接口本身不难难的是所有细节都恰好被处理好。一个能稳定跑半年的翻译服务胜过一个偶尔翻车但指标漂亮的项目。本文还有配套的精品资源点击获取