ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python调用Bing翻译网页版:免费API替代方案与实现详解

Python调用Bing翻译网页版:免费API替代方案与实现详解 1. 项目概述为什么我们需要一个免费的Bing翻译方案如果你正在用Python处理多语言文本无论是分析海外社交媒体数据、本地化你的应用界面还是处理一份多语言的文档翻译API都是一个绕不开的需求。市面上成熟的方案不少比如Google Cloud Translation、DeepL功能强大但价格不菲对于个人开发者、学生或者小项目来说成本是个大问题。而微软Azure的认知服务翻译器虽然也提供了免费额度但需要绑定信用卡、创建Azure资源流程相对复杂而且免费额度用完后一不小心就可能产生费用。于是很多人把目光投向了Bing翻译。作为微软旗下的产品它本身提供了一个公开的网页版翻译界面。那么有没有可能绕过官方的付费API直接通过Python调用这个网页版背后的服务实现一个“免费”的翻译功能呢这正是我们今天要深入探讨的核心。我必须强调这种方法本质上是模拟浏览器访问Bing翻译网页解析其返回结果并非使用官方、稳定、有服务保障的API。它适用于个人学习、小批量、非商业、对稳定性要求不高的场景。如果你需要高并发、高可靠性的生产级翻译服务请务必考虑Azure Translator等官方付费方案。2. 核心思路拆解网页翻译是如何工作的在动手写代码之前我们得先搞清楚Bing翻译网页是怎么完成一次翻译的。这能帮助我们找到模拟的切入点。2.1 从用户操作到网络请求当你在浏览器打开https://www.bing.com/translator输入一段文字并点击翻译时浏览器并不会刷新整个页面。现代网页普遍采用Ajax技术浏览器会悄悄地向服务器发送一个HTTP请求服务器处理后将翻译结果以数据通常是JSON格式的形式返回浏览器再用JavaScript把结果显示在页面上。我们的目标就是用Python程序扮演这个“浏览器”的角色自动完成“构造请求 - 发送请求 - 解析响应”这一系列动作。关键在于我们需要知道请求发送到哪里(URL)请求里要带什么信息(Headers, Parameters, Data)服务器返回的数据长什么样(如何从中提取翻译结果)2.2 关键信息捕获使用开发者工具要回答上面的问题我们必须请出前端开发者的“神器”——浏览器的开发者工具按F12打开。我们以Chrome浏览器为例进行一次手动翻译并观察网络活动。打开Bing翻译页面并保持开发者工具的“网络(Network)”标签页开启记得勾选“保留日志(Preserve log)”。在翻译框输入“Hello world”选择从“英语”到“中文(简体)”点击翻译按钮。在“网络”标签页中你会看到一系列新出现的请求。我们需要寻找那个看起来像是提交翻译数据的请求。它通常是一个POST请求名称可能包含translate或ttranslatev3。点击这个请求查看其“标头(Headers)”和“负载(Payload)”或“预览(Preview)”。通过分析我们可以发现核心的请求信息。这里以我最近一次分析为例请注意Bing的接口细节可能会随时间变化但原理相通请求URL:https://www.bing.com/ttranslatev3请求方法:POST请求头(Headers): 其中User-Agent用于标识客户端、Content-Type告知服务器发送的数据格式至关重要。通常还会有一个Referer头标明请求来源。请求参数(Query String Parameters): URL中可能附带一些参数如isVertical1IG...IID...。其中IG和IID看起来像是某种会话或实例标识符可能从页面初始加载的响应中获取。请求体(Request Body): 这是最关键的部分通常是form-data或x-www-form-urlencoded格式。里面包含了我们输入的文本、源语言和目标语言代码。例如textHello worldfromLangentoLangzh-Hans服务器返回的响应体通常是一个JSON数组里面包含了翻译结果、检测到的语言等信息。我们的任务就是从这段JSON里把翻译文本提取出来。注意直接模拟这个ttranslatev3接口有时会遇到障碍比如需要处理动态生成的IG、IID参数或者遇到验证机制。因此更稳健的一种方法是模拟整个页面初始化流程先获取必要的令牌(token)和会话ID。3. 方案选型与工具准备基于上述分析我们有两种主要的实现路径。3.1 方案一直接请求翻译接口简单但不稳定这种方法就是直接向观察到的翻译接口如ttranslatev3发送POST请求。它的优点是直接、代码简单。但缺点非常明显极其脆弱。Bing可以随时更改这个接口的地址、参数格式或增加验证如需要从首页获取动态密钥导致你的脚本突然失效。它仅适用于临时、一次性的任务。3.2 方案二模拟完整会话推荐更稳定这种方法更接近真实浏览器的行为首先用程序访问https://www.bing.com/translator首页。从返回的HTML页面中解析出当前会话所需的关键令牌Token和ID。这些信息往往隐藏在页面内的某个script标签或全局变量中。然后使用这些获取到的令牌构造一个格式正确的请求发送到翻译接口。最后解析接口返回的JSON数据。这个方案虽然步骤稍多但因为它模拟了正常的用户访问流程所以稳定性更高不易因接口微调而失效。我们将以这个方案作为重点进行实现。3.3 工具库选择为什么是requests和BeautifulSouprequests: Python中最著名、最易用的HTTP库。我们将用它来发送所有的GET和POST请求模拟网络交互。它比Python内置的urllib更加人性化。BeautifulSoup4(bs4): 一个强大的HTML/XML解析库。当我们需要从Bing翻译首页的HTML代码中提取隐藏的令牌和ID时BeautifulSoup能帮助我们轻松地定位和获取这些信息。安装它们非常简单只需在命令行中执行pip install requests beautifulsoup44. 分步实现构建一个稳健的免费翻译函数现在让我们开始动手编写代码。我会将整个过程封装成一个易于使用的函数translate_text(text, to_langzh-Hans, from_langauto-detect)。4.1 第一步获取会话令牌与关键参数这是整个流程中最关键的一步。我们需要先“拜访”一下Bing翻译的主页拿到“入场券”。import requests from bs4 import BeautifulSoup import re import json def get_bing_translation_token(): 访问Bing翻译首页并从中提取翻译所需的关键令牌IG, IID, key, token等。 返回一个包含这些参数的字典。 session requests.Session() # 设置一个合理的浏览器User-Agent避免被简单的反爬机制屏蔽 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 } # 1. 访问翻译首页 homepage_url https://www.bing.com/translator try: response session.get(homepage_url, headersheaders, timeout10) response.raise_for_status() # 检查请求是否成功 except requests.exceptions.RequestException as e: print(f访问首页失败: {e}) return None soup BeautifulSoup(response.text, html.parser) # 2. 关键信息通常藏在script标签的JavaScript变量里 # 我们需要找到包含“IG”、“IID”、“params_AbusePreventionHelper”等信息的代码段 translation_params {} # 方法A尝试通过正则表达式查找IG和IID常见于URL参数 # 在页面HTML中搜索类似 IG:...,IID:... 的字符串 script_tags soup.find_all(script) for script in script_tags: if script.string: # 查找IG (可能是一个长字符串) ig_match re.search(rIG:([^]), script.string) if ig_match: translation_params[IG] ig_match.group(1) # 查找IID (通常像 translator.5023) iid_match re.search(rIID:([^]), script.string) if iid_match: translation_params[IID] iid_match.group(1) # 查找更重要的防滥用预防密钥和令牌 # 它可能是一个JSON对象包含“key”和“token” params_match re.search(rparams_AbusePreventionHelper\s*\s*(\{.*?\});, script.string, re.DOTALL) if params_match: try: abuse_prevention_params json.loads(params_match.group(1)) translation_params[key] abuse_prevention_params.get(key) translation_params[token] abuse_prevention_params.get(token) # 有时这个令牌也叫‘token’有时是‘authorization’ except json.JSONDecodeError: pass # 方法B如果方法A没找到尝试另一种常见模式——从全局变量window 中获取 if not translation_params.get(key): for script in script_tags: if script.string and var in script.string and params_ in script.string: lines script.string.split(\n) for line in lines: if params_ in line and in line: # 简化处理寻找key和token的赋值 key_match re.search(rkey\s*:\s*([^]), line) token_match re.search(rtoken\s*:\s*([^]), line) if key_match: translation_params[key] key_match.group(1) if token_match: translation_params[token] token_match.group(1) # 3. 确保我们至少找到了key和token这是当前经验上最必须的参数 if not translation_params.get(key) or not translation_params.get(token): print(警告未能从页面中提取到关键的 key 或 token。接口可能已更新。) # 可以尝试回退到更简单的、不需要这些参数的旧接口格式但成功率低 # 例如有些资料显示旧的接口是 /ttranslatev3?isVertical1... # 将session也返回以便后续请求保持相同的会话上下文如Cookies return translation_params, session实操心得Bing翻译前端的JavaScript代码结构可能会更新导致提取令牌的正则表达式失效。如果上述代码无法找到key和token你需要手动打开开发者工具在“网络”标签页中仔细查看首页加载后第一个或第二个请求的响应内容通常是某个.js文件或直接是HTML然后搜索AbusePreventionHelper或IG、IID等关键词根据最新的代码结构调整正则表达式。这是一个“猫鼠游戏”也是此类非官方方法最大的维护成本。4.2 第二步构造并发送翻译请求拿到“入场券”后我们就可以正式请求翻译服务了。def translate_text(text, to_langzh-Hans, from_langauto-detect, max_retry2): 使用Bing翻译网页版接口翻译文本。 参数: text: 要翻译的文本字符串。 to_lang: 目标语言代码例如 zh-Hans(简体中文), en(英语), ja(日语), fr(法语)。 from_lang: 源语言代码默认 auto-detect 为自动检测。 max_retry: 获取令牌失败时的重试次数。 返回: 翻译后的文本字符串如果失败则返回None。 # 0. 输入校验 if not text or not isinstance(text, str): print(错误输入文本无效。) return None # 1. 获取翻译令牌和会话 translation_params, session None, None for i in range(max_retry): translation_params, session get_bing_translation_token() if translation_params and session: break print(f第{i1}次获取令牌失败重试...) if not translation_params or not session: print(错误无法获取翻译所需的会话参数。) return None # 2. 准备请求URL和头部 # 注意接口地址可能变化目前是 /ttranslatev3 translate_url https://www.bing.com/ttranslatev3 headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36, Content-Type: application/x-www-form-urlencoded, Referer: https://www.bing.com/translator, Accept: application/json, } # 3. 准备请求体数据 # 根据抓包分析必需的字段包括 text, fromLang, toLang # 此外还需要包含从首页获取的 key 和 token form_data { text: text, fromLang: from_lang, to: to_lang, } # 添加防滥用预防参数如果获取到了 if translation_params.get(key): form_data[key] translation_params[key] if translation_params.get(token): # 注意有时参数名是 ‘token’有时需要放在头部 ‘Authorization’。 # 根据当前分析放在form-data里是可行的。 form_data[token] translation_params[token] # 4. 可选添加IG和IID作为查询参数某些接口版本需要 # query_params {} # if translation_params.get(IG): # query_params[IG] translation_params[IG] # if translation_params.get(IID): # query_params[IID] translation_params[IID] # 如果接口需要可以将其拼接到URL后面如 translate_url ? urlencode(query_params) # 5. 发送POST请求 try: response session.post( translate_url, headersheaders, dataform_data, # paramsquery_params, # 如果需要查询参数则启用 timeout15 ) response.raise_for_status() # 6. 解析响应 result_json response.json() # 响应结构通常是一个列表第一个元素是一个字典其中包含翻译结果 # 例如: [{detectedLanguage: {language: en, score: 1.0}, translations: [{text: 你好世界, to: zh-Hans}]}] if isinstance(result_json, list) and len(result_json) 0: first_item result_json[0] if translations in first_item and isinstance(first_item[translations], list): translated_text first_item[translations][0].get(text) if translated_text: return translated_text # 如果上述解析失败打印响应以便调试 print(f解析响应失败原始响应: {result_json}) return None except requests.exceptions.JSONDecodeError: print(错误服务器返回的不是有效的JSON。响应文本, response.text[:200]) return None except requests.exceptions.RequestException as e: print(f翻译请求失败: {e}) return None4.3 第三步测试与使用现在我们可以像调用普通函数一样使用这个翻译工具了。if __name__ __main__: # 示例1英译中 result translate_text(Hello, world! This is a test of Bing Translator., to_langzh-Hans) if result: print(f翻译结果{result}) # 示例2中译英 result2 translate_text(这是一个Python调用Bing翻译的示例程序。, to_langen) if result2: print(fTranslation: {result2}) # 示例3自动检测语言并翻译成日语 result3 translate_text(Bonjour le monde, to_langja) if result3: print(f翻訳結果{result3})5. 高级技巧与优化策略基础的调用已经实现但在实际使用中你可能会遇到各种问题。下面分享一些提升脚本健壮性和可用性的经验。5.1 处理长文本与分句Bing翻译网页接口对单次请求的文本长度有限制通常在5000字符左右。直接提交很长的文本可能会失败。解决方案实现自动分句翻译import re def translate_long_text(long_text, to_lang, from_langauto-detect, max_chunk_len4000): 翻译长文本通过按句子或长度分块处理。 这是一个简单实现按标点符号和最大长度分块。 # 简单的分句逻辑按句号、问号、感叹号、换行分割并保留分隔符 sentence_endings r(?[。.!?])\s sentences re.split(sentence_endings, long_text) chunks [] current_chunk for sentence in sentences: # 如果当前块加上新句子长度超限且当前块不为空则保存当前块并开始新块 if len(current_chunk) len(sentence) max_chunk_len and current_chunk: chunks.append(current_chunk) current_chunk sentence else: current_chunk sentence if current_chunk: chunks.append(current_chunk) # 翻译每个块 translated_chunks [] for chunk in chunks: if chunk.strip(): # 忽略空块 translated translate_text(chunk, to_lang, from_lang) if translated: translated_chunks.append(translated) else: # 如果某块翻译失败可以记录日志或加入原文 translated_chunks.append(f[翻译失败: {chunk[:50]}...]) # 建议在块之间加入短暂延时避免请求过快 # time.sleep(0.5) return .join(translated_chunks) # 或用换行符连接根据原文格式决定5.2 设置请求间隔与错误重试频繁、快速地发送请求会触发Bing服务器的反爬机制导致返回429 Too Many Requests或403 Forbidden错误。优化策略添加延时在连续翻译请求之间使用time.sleep(random.uniform(1, 3))添加随机延时模拟人类操作。实现重试机制对于网络错误或特定的服务器错误如429、503可以实现一个带指数退避的重试逻辑。使用代理IP池如果翻译需求量非常大考虑使用多个代理IP轮询发送请求但这会大大增加复杂度和成本。import time import random def robust_translate(text, to_lang, from_langauto-detect, retries3): 一个带有简单重试和延时的翻译包装函数 for attempt in range(retries): try: result translate_text(text, to_lang, from_lang) if result: return result else: # 如果返回None可能是令牌获取失败也触发重试 raise ValueError(Translation returned None) except (requests.exceptions.RequestException, ValueError) as e: if attempt retries - 1: wait_time (2 ** attempt) random.random() # 指数退避加随机抖动 print(f第{attempt1}次尝试失败 ({e})等待{wait_time:.2f}秒后重试...) time.sleep(wait_time) else: print(f所有{retries}次尝试均失败。) raise return None5.3 语言代码对照表你需要知道目标语言对应的代码。Bing翻译使用的语言代码通常是符合BCP 47标准的语言标签。语言代码备注简体中文zh-Hans最常用繁体中文zh-Hant英语en日语ja韩语ko法语fr西班牙语es德语de俄语ru自动检测auto-detect源语言参数你可以在Bing翻译网页上手动切换语言然后观察网络请求中fromLang和to参数的变化来确认最新的语言代码。6. 常见问题与排查指南在实际使用中你几乎一定会遇到下面这些问题。这里提供一个快速排查的思路。6.1 错误KeyError或无法提取key/token症状get_bing_translation_token函数返回的字典中key或token为空。原因Bing翻译前端代码已更新正则表达式无法匹配到新的变量名或数据结构。排查手动打开https://www.bing.com/translator。按F12打开开发者工具切换到“网络(Network)”面板刷新页面。在筛选器里选择“文档(Doc)”或“全部(All)”找到第一个请求通常是translator。在“响应(Response)”标签页里搜索AbusePreventionHelper或params_。找到包含key和token的JavaScript对象。观察它的结构和新变量名。根据新结构修改get_bing_translation_token函数中的正则表达式或解析逻辑。6.2 错误429 Too Many Requests症状请求翻译接口时返回状态码429。原因请求频率过高触发了服务器的速率限制。解决立即降低请求频率在每次翻译请求后增加time.sleep()例如time.sleep(random.uniform(2, 5))。检查代码逻辑是否在循环中无延迟地疯狂调用函数使用会话(Session)确保使用requests.Session()它有助于保持连接和Cookies有时比每次新建连接行为更好。如果问题持续可能需要更换IP地址或等待一段时间再试。6.3 错误403 Forbidden症状请求被拒绝返回状态码403。原因请求头不完整或异常缺少必要的Referer、User-Agent或Accept头。令牌无效或过期从首页获取的key/token已经失效。每个令牌可能有很短的有效期或使用次数限制。IP或行为被标记你的IP地址或请求模式被识别为爬虫。解决检查请求头确保headers字典包含了从浏览器抓包中看到的所有关键头信息特别是Referer必须为https://www.bing.com/translator。重新获取令牌在每次翻译请求前都调用一次get_bing_translation_token获取最新的令牌。虽然效率低但更稳定。模拟更真实的行为在获取令牌和发送翻译请求之间增加随机延时并使用更常见的User-Agent。6.4 错误返回结果解析失败症状translate_text函数能收到响应但无法从JSON中提取出翻译文本返回None。原因翻译接口返回的JSON结构发生了变化。排查在translate_text函数的try块内打印出result_json的完整内容。分析这个JSON的结构找到存放翻译文本的新路径。根据新结构修改解析代码。例如可能变成了result_json[0][‘translations’][0][‘text’]或者有其他嵌套方式。6.5 性能与可靠性权衡痛点稳定性和便利性不可兼得。越稳定的方案如每次翻译前获取新令牌速度越慢。建议对于一次性或低频任务采用“每次获取令牌”的模式确保成功率。对于需要翻译大量短句的任务可以尝试“一次获取令牌翻译多个句子”的模式但在连续翻译10-20句后主动重新获取一次令牌以防过期。同时务必在每句之间添加显著延时如1-3秒。终极建议如果翻译需求成为你项目的核心且频繁的功能请认真考虑申请微软Azure认知服务翻译器的免费层。它每月有200万字符的免费额度拥有稳定的API、官方SDK和支持远比维护一个脆弱的网页爬虫脚本要省心、专业得多。这个基于Python和requests库调用Bing翻译的方案是一个很好的学习案例它涉及了网络爬虫、HTTP协议、数据解析和错误处理等多个知识点。它能解决临时性、小规模的翻译需求但请时刻记住它的“非官方”属性做好接口变动的心理准备并将关键功能与这个翻译模块解耦以便未来替换为更稳定的服务。
返回列表