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程序中,下一篇文章,我们将会把这个脚本整理一下,放到脚本工具包中供翻译器调用,且会加装一些网络状况的判断。
如果你看到这里,说明你又变强了!希望你变得更强,感谢你的观看,共同进步!