此博客仅为我业余记录文章所用,发布到此,仅供网友阅读参考,如有侵权,请通知我,我会删掉。
打铁趁热,姊妹篇传送门:python爬虫入门 ✦ 某道翻译
1.本文思路
1.先从抓包里面Network—XHR里面的formdata表单分析,需要获取的参数为sign和token。
2.复制sign或token关键字在右上角的search搜索,抓取相关的JS文件
3.将找到的 生成sign或token的函数代码 直接保存到本地文件,利用execjs模块执行js代码,进行调试,从而找出规律
4.通过分析得出 sign和token的值在网页源代码可以请求得到。
1.1 分析url
本次文章链接为 aHR0cHMlM0EvL2ZhbnlpLmJhaWR1LmNvbS8=(base64解密即可)
(1) 在某度翻译页面,点击F12—Network—XHR,然后在输入框输入 student(任意输入),查看抓包到的数据,可以看到一个名为v2transapi的包,点击它,查看Preview。确定了这个是我们最终需要获取的数据包。下面就着手去获取它。
(2) 接下来我们的移动到headers这里,可以看到响应内容的url,该请求方法为post,下面的画框的Form_Data就是我们所需要的分析的表单内容啦。
(3) 来分析一下 student和teacher的Form_Data表单。
通过比对两组表单数据,sign和token(token虽然不变,但是也找出来最好)是我们所需要获取的数据。query则为我们输入需要的翻译的单词,接下来我们看一下如果获取sign,token这两个参数。
from: en ## student
to: zh
query: student
transtype: realtime
simple_means_flag: 3
sign: 767469.1005276
token: 3d154702e04333770e2c6be7c28b0d53
from: en ## teacher
to: zh
query: teacher
transtype: enter
simple_means_flag: 3
sign: 384259.81458
token: 3d154702e04333770e2c6be7c28b0d53
1.2 获取js
(1) 点击该页面右上角,然后点击search,会弹出下图这个界面。然后再在搜索框输入关键字 sign:,选择弹出的第一个。最后点击画红色框框的花括号,(它的作用是将代码格式化,变得好看。)
(2) 因为代码很长,很难看懂。这个时候只有选择打断点 来分析一下。
可以看到,js代码很长。 这里的sign = 函数m(a),在下面划红框处,打上两个断点,然后再输入框输入任意单词,查看现象。看到我们的函数值m(a)中的a就是我们所输入的单词。
(3) 将鼠标轻轻移动到sign: m(a)这里,可以看到会弹出一个 **f e(r)**的函数,鼠标左键点击它。然后会跳转到该js函数所在的代码行。
(4) 仔细看一下这个图片画框的地方, 然后对比一下前面的 student 中的 sign:767469.1005276,下图画框的中间那个 “.” 对应的就是 sign的值中间的 "."
(5) 可是js代码超长,看不懂。这个时候我们就需要将 与 sign相关的代码块复制下来,保存到本地。
1.3 解析js
(1) 将前面的那一串js代码保存为js格式的文件。
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
!!!!!
这个时候,解析js代码的 execjs模块要登场了!下面的代码是execjs的简单使用。
import execjs
# 打开刚才保存的baidu.js的文件
with open('baidu.js', 'r') as f:
js = f.read()
# 创建对象
js_data = execjs.compile(js)
# eval的作用是将字符串当成表达式来执行
sign = js_data.eval('e("student")') #e是js代码的函数e,student为输入的单词
print(sign)
(2) ??? 报错了?? 看了报错内容为 i未定义。这个时候就去 刚才保存的baidu.js里面找原因。
(3) 找 i,找 i, 找i。。因为是i报错了。!!!
看到 i了。这里的 U = i = window[ l],而这个 l又等于i = “” “”+ String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107)。。这个时候将这一串编码代码复制到F12—source里面看一下是什么。
(4) 可以看到,我们复制过来的一串长长的编码代码,解码后为 gtk 所以我们的U = i = window[ gtk], 这个时候去网页源代码搜索一下window[ gtk]。
(5) 可以看到window[ gtk]为一串长长的数字320305.131321201,现在我们将这一串数字复制到 baidu.js里面
(6) 因为U = i = window[ gtk]=‘320305.131321201’,所以直接就将这串数字赋值给U
(7) 再次执行我们的代码,嗯。有成功打印结果了!!!!!这一串打印出来的数字是不是很熟悉呢。。返回前面看一下,是不是和我们的 student的Form_Data里面的sign值一样呢!!好,那现在我们就成功解决了这个sign了,接下来就是获取token了。
from: en ## student
to: zh
query: student
transtype: realtime
simple_means_flag: 3
sign: 767469.1005276
token: 3d154702e04333770e2c6be7c28b0d53
(8) 再次回到js代码,看到token的值为 window.common.token。好家伙,我们就这一串代码去网页源代码搜索一下看看。
(9) 看到token了。到了现在,我们的js分析已经完成了。代码也相当于完成99%了!
2.完整代码
import re
import execjs
import requests
class BaiuSpider(object):
def __init__(self):
self.base_url = 'https://fanyi.baidu.com'
self.translate = 'https://fanyi.baidu.com/v2transapi'
self.headers = {
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'zh-CN,zh;q=0.9',
'cache-control': 'max-age=0',
'cookie': 'cookie填写自己的',
'referer': 'https://fanyi.baidu.com/',
'upgrade-insecure-requests': '1',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36',
}
def get_token_gtk(self):
res = requests.get(self.base_url, headers=self.headers).text
token = re.findall("window.*?token: '(.*?)'", res, re.S)
gtk = re.findall("window.gtk = '(.*?)';</script>", res, re.S)
print(gtk[0], token[0])
return token[0], gtk[0]
def get_sign(self, word, token):
with open('baidu.js', 'r') as f:
js = f.read()
js_data = execjs.compile(js)
sign = js_data.eval('e("{}","{}")'.format(word, token))
return sign
def main(self, word, fro, to):
token, gtk = self.get_token_gtk()
sign = self.get_sign(word, gtk)
form_data = {
'from': fro,
'to': to,
'query': word,
'transtype': 'realtime',
'simple_means_flag': '3',
'sign': sign,
'token': token
}
res = requests.post(self.translate, data=form_data, headers=self.headers).json()
# print(res)
print(res['trans_result']['data'][0]['dst'])
if __name__ == '__main__':
spider = BaiuSpider()
choice = input("1.英译汉 2.汉译英:")
word = input("请输入你要翻译的单词:")
if choice == '1':
fro, to = 'en', 'zh'
elif choice == '2':
fro, to = 'zh', 'en'
spider.main(word, fro, to)
文章很长,难免有出错的地方,恳请各位为我指正错误。
有不懂的地方欢迎在下方留言或一起讨论。