PyQt5实战——翻译的实现,成功爬取微软翻译(可长期使用)经验总结(九)
个人博客:苏三有春的博客
系类往期文章:
PyQt5实战——多脚本集合包,前言与环境配置(一)
PyQt5实战——多脚本集合包,UI以及工程布局(二)
PyQt5实战——多脚本集合包,程序入口QMainWindow(三)
PyQt5实战——操作台打印重定向,主界面以及stacklayout使用(四)
PyQt5实战——UTF-8编码器UI页面设计以及按钮连接(五)
PyQt5实战——UTF-8编码器功能的实现(六)
PyQt5实战——翻译器的UI页面设计以及代码实现(七)
PyQt5实战——翻译的实现,第一次爬取微软翻译经验总结(八)
前言
本文笔者吸取了第一次爬取微软翻译的经验,发现在对微软翻译进行请求的时候,URL会随着会话结束而重新生成,这一点是本文需要解决的内容,且除了URL中出现的IG和IID两个数据外,在请求的表单数据中,还有key和token两个数据也在动态变化。本文旨在追踪这几个数据在何时被发送,如何被获取。
分析
首先,重新打开浏览器自带的开发者工具,随便翻译一词,让客户端发送一次翻译请求ttranslatev3,可以发现,这次URL与前一篇文章PyQt5实战——翻译的实现,第一次爬取微软翻译经验总结(八)的又不一致
https://cn.bing.com/ttranslatev3?isVertical=1&&IG=DFFF2F46AAE0482491F67EEEB26C249C&IID=translator.5025
笔者借助开发者工具自带的搜索框进行搜索,看看我们需要的数据在哪里出现过
除了上一篇文章中提到的IG和IID两个数据外,我们还需要找到token和key两个数据,在ttranslatev3响应请求中,可以看到我们发送请求时,请求表单除了携带需要翻译的文本,翻译前的语种,翻译后的语种外,还需携带两个特殊的信息

至于tryFetchingGenderDebiasedTranslations一直为true,因此直接填写即可
IG
找到IG所在
首先看看IG在哪里出现过,将IG的数据DFFF2F46AAE0482491F67EEEB26C249C复制进搜索框查询,得到以下信息

可以发现,搜索出来的大部分请求中,这一串数据都是出现在URL与path中的,也就是说,这些请求中,IG数据也是被使用的,并不是出自于这些请求,继续向下滑动,找到了一个translator的包

如果你点击进去,就会发现,这其实就是访问该页面的第一个请求响应,它的html数据构建了整个页面

现在我们查看IG数据在这个响应的哪里,点击刚刚搜索的地方,会自动跳转到response出现了相同信息的地方,如下图所示:

因此,现在重新确认一下目标:目标从“找到IG数据的出处”变更为“获取IG数据”。
请求获取IG数据
来观察一下这个请求响应,回顾一下上一篇文章,我们在请求时需要些什么数据:
URL、User-Agent、表单数据
那我们依次来找这个请求所需要的数据,首先看标头:

URL
这个URL携带的信息很好猜,https://cn.bing.com/translator是访问的主机,即微软搜索引擎bing的翻译页面,?表示后面携带了多个参数,ref=TThis这通常表示一个参考信息或来源标识符。可能是用来跟踪用户从哪个链接访问了翻译工具,text表示默认的翻译文本,from表示翻译前的语种,to表示目标语种。可以看到,这里后面携带的三个信息,正好是打开网页时的默认信息

“输入文本”是背景,实际上并没有东西在这里。
可以猜测,每次访问这个页面,URL大概率是不会发生变化的,没有携带什么特殊的信息。经过反复的刷新和测试,验证了这个猜想。
User-Agent
为什么User-Agent会是一样的?需不需要担心它会不会变化?来看一下User-Agent的定义:
在进行网页爬虫时,
User-Agent是一个非常重要的 HTTP 请求头字段,它的主要作用是向服务器提供有关请求者(通常是浏览器或爬虫)的一些信息。具体来说,它会告诉服务器,发出请求的客户端是什么类型的设备,操作系统,浏览器等。不同的服务器和网站可能根据User-Agent来决定如何响应请求,比如返回不同的内容、样式,或者限制对某些类型客户端的访问。
User-Agent的作用总结:
- 识别客户端:
User-Agent向服务器表明请求是由哪个客户端发出的。对于不同的浏览器、操作系统或设备,User-Agent会有所不同。例如,Chrome、Firefox、Safari、IE 等不同浏览器会有不同的User-Agent字符串。- 避免被识别为爬虫: 网站可能会根据
User-Agent来识别是否是爬虫程序。很多爬虫程序没有设置真实的User-Agent,或者User-Agent字符串看起来像是一个自动化脚本(比如 Python 的requests库默认User-Agent是一个简单的字符串)。一些网站会使用这一点来检测并阻止爬虫请求。因此,为了模拟浏览器,爬虫通常会伪装成浏览器的User-Agent,避免被网站识别为爬虫。- 返回适配的内容: 根据
User-Agent,服务器可以返回特定格式的内容。比如,移动设备和桌面设备通常会看到不同版本的网页,甚至不同的图片大小和样式。通过查看User-Agent,服务器可以判断请求来自于手机、平板、桌面或其他设备,并返回不同的页面样式或功能。- 分辨设备和浏览器版本:
User-Agent可以帮助服务器确定访问者的设备类型、操作系统及浏览器版本,从而优化响应内容。比如,某些页面可能会针对不同的操作系统(如 Windows、macOS、Linux)或不同版本的浏览器提供特定的网页布局或 JavaScript 功能。
可以看出,一些服务器会根据User-Agent来判断访问请求是不是来自人类或自动化脚本,可做一些反爬虫操作。我们从浏览器获取的请求信息中包含的User-Agent,表明了这段请求时来自浏览器,而非自动化脚本,因此,我们可以回答上面的问题:1.User-Agent一样是因为我们今天与昨天用的都是同一个浏览器访问,它代表了“该请求来自Edge浏览器”。2.无需担心它会发生变化,除非浏览器更新会更改这项数据,而这大概率是不会发生的。
代码实现
首先,先获取整个response的html数据,把它写在一个单独的文件里,(数据量太大,操作台无法查找相应的数据),有些导入的模块会在后面的代码中用到,这仅是完整代码的一部分
import requests
import re
from bs4 import BeautifulSoup
from urllib import response
import urllib.request
import json
url = "https://cn.bing.com/translator?ref=TThis&text=&from=zh-Hans&to=en"
header = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0"}
response = requests.get(url,headers=header,data={})
response.raise_for_status()
html = response.text
with open("translator.html", "w", encoding="utf-8") as f:f.write(html)
获取到相应的HTML,直接搜索IG

现在,我们找到了这个数据,用正则表达式将数据获取,其中re.search方法是调用第三方库re
ig = re.search(r'IG:"(\w+)"',html).group(1) # 使用正则表达式在html文件中查找IG数据并获取
IID
我们用同样地办法查找IID的所在地并获取它
找到IID的所在

找到IID数据的所在,依然在translator请求响应中,这就好办了,因为该请求的完整相应已经被我们获取了,只要找到相应的位置即可。

刚刚获取的HTML文件中,你可以找到多个带有data-iid属性的<div>,因此,我们需要更加详细的信息来确认其位置,比如利用前面的id=" tta_outGDCont",
代码实现
可以使用第三方库BeautifulSoup,获取html格式数据中特定的属性,比如data-iid
soup = BeautifulSoup(html, "html.parser")
dev_element = soup.find("div", id = "tta_outGDCont")
data_iid = dev_element.attrs["data-iid"]
print("data_iid:"+data_iid)
我们来解释一下soup = BeautifulSoup(html, "html.parser")这一段代码
1. BeautifulSoup
BeautifulSoup是一个 Python 库,主要用于从 HTML 或 XML 文档中提取数据。它提供了许多方法来帮助你遍历、搜索和修改 HTML/XML 文档的内容。2. html
html是传入BeautifulSoup构造函数的参数,通常是一个包含 HTML 内容的字符串。它代表了待解析的 HTML 文档。可以是从文件读取的内容,或者是通过网络请求获取的 HTML 页面。3. “html.parser”
"html.parser"是BeautifulSoup的一个解析器(parser)。它告诉BeautifulSoup使用 Python 内建的 HTML 解析器来解析传入的 HTML 文档。这个解析器是一个快速且有效的解析工具,但对于一些特殊的 HTML,可能处理得不如其他第三方解析器(如lxml或html5lib)精准。
"html.parser"选项是 Python 默认的解析器,但如果你安装了lxml或html5lib等库,也可以指定其他解析器。例如:
"lxml":使用lxml库的 HTML 解析器。"html5lib":使用html5lib库,它更宽容于不规范的 HTML 代码。4. 最终效果
这行代码的作用是:通过
BeautifulSoup库,将传入的 HTML 字符串html解析成一个BeautifulSoup对象,并指定使用内建的html.parser解析器。解析后的soup对象可以用来方便地操作和提取 HTML 内容。
剩下的代码看方法名称也很好理解它是做什么的
token与key
找到token与key的所在
我们用相同的办法,通过搜索框查找token的所在地,发现,这个信息同样存在于translator请求响应中:

如果你仔细一点,你会发现,token前面那串数字,就是我们下一个要找的key!真是得来全不费工夫,剩下的两个数据被我们一次性找到了,接下来就是获取它们。
代码实现
pattern = r'var params_AbusePreventionHelper = \[(\d+),"([^"]+)",\d+\];'
token = re.findall(pattern, html)
print("key:"+token[0][0])
print("token:"+token[0][1])
同样地,我们使用正则表达式,查找var params_AbusePreventionHelper后面的两个数据,放在token列表中。
小结
至此,我们找到了我们所需的全部数据,接下来只需要将IG与IID填进URL中,将token与key填进表单中,就可发送完整的请求,伪装成正常的浏览器请求了。
请求与获取相应
代码实现
url = "https://cn.bing.com/ttranslatev3?isVertical=1&&IG="+ig+"&IID="+data_iid
print(url)
header = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0"}
data = {"fromLang":"zh-Hans","to":"en","token":token[0][1],"key":token[0][0],"text":"今天的天气","tryFetchingGenderDebiasedTranslations":"true"}
print(data)
data = urllib.parse.urlencode(data).encode("utf-8")
req = urllib.request.Request(url, data, headers=header)
response = urllib.request.urlopen(req)
html = response.read().decode("utf-8")
target = json.loads(html)
print(target[0]['translations'][0]['text'])
根据上一篇文章的经验,以及本文上述的分析:
- URL需要根据上文所获取的IG与IID进行动态变换
data数据,将我们上面获取的token与key分别放入字典中- 对数据进行UTF-8编码转换格式
- 发送请求
- 获取响应并进行UTF-8解码
- 转换JSON格式
- 获取数据
如果将进行UTF-8解码后的数据完整打印出来,将会是:
[{"translations":[{"text":"Today's weather","to":"en","sentLen":{"srcSentLen":[5],"transSentLen":[15]}}],"detectedLanguage":{"language":"zh-Hans"}},{"inputTransliteration":"jīntiān de tiānqì"}
]
我们要的就是translations列表下的第一个字典中text对应的value
完整代码
from csv import Error
from email.policy import HTTP
from tkinter import E
from urllib.error import URLError
import requests
import re
from bs4 import BeautifulSoup
from urllib import response
import urllib.request
import jsonclass Translation:def __init__(self,content): self.translating(content)def translating(content,lfrom,lto): if content == "":return "请输入内容"langfrom = {"自动检测":"auto-detect","中文":"zh-Hans","English":"en"}langto = {"中文":"zh-Hans","English":"en"} url = "https://cn.bing.com/translator?ref=TThis&text=&from=zh-Hans&to=en"header = {"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0"}try:response = requests.get(url,headers=header,data={},timeout=5)except Exception as e:print(f"There are something wrong with the network: {e}")return "website is not reachable"html = response.textsoup = BeautifulSoup(html, "html.parser")dev_element = soup.find("div", id = "tta_outGDCont")data_iid = dev_element.attrs["data-iid"]print("data_iid:"+data_iid)ig = re.search(r'IG:"(\w+)"',html).group(1)print("IG:"+ig)pattern = r'var params_AbusePreventionHelper = \[(\d+),"([^"]+)",\d+\];'token = re.findall(pattern, html)print("key:"+token[0][0])print("token:"+token[0][1])url = "https://cn.bing.com/ttranslatev3?isVertical=1&&IG="+ig+"&IID="+data_iidprint(url)header = {"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0"}data = {"fromLang":langfrom[lfrom],"to":langto[lto],"token":token[0][1],"key":token[0][0],"text":content,"tryFetchingGenderDebiasedTranslations":"true"}print(data)data = urllib.parse.urlencode(data).encode("utf-8")try:req = urllib.request.Request(url, data, headers=header)response = urllib.request.urlopen(req)html = response.read().decode("utf-8")target = json.loads(html)except Exception as e:print(f'There are something wrong with the network: {e}')return "website is not reachable"try:print("translations:"+target[0]['translations'][0]['text'])except KeyError:print(target)return "something was wrong"return target[0]['translations'][0]['text']
结语
这次,我们完成了对微软翻译的完整爬虫,且可以完美多次长时间地运行,这个脚本功能已经完善,只是还没有嵌入到GUI程序中,下一篇文章,我们将会把这个脚本整理一下,放到脚本工具包中供翻译器调用,且会加装一些网络状况的判断。
如果你看到这里,说明你又变强了!希望你变得更强,感谢你的观看,共同进步!
