1.F12抓包,找到json的地址,观察Form表单数据
1.1)POST地址:https://fanyi.baidu.com/v2transapi
1.2)Form表单数据(多次抓取在变的字段)
from: en
to: zh
query: tiger
transtype: realtime
simple_means_flag: 3
sign: 505705.218200 #这个是如何生成的?
token: a33ce708e73f75d9dbd4b25d0c80b44d #基本固定,不同浏览器不一样
domain: common
2.抓取相关js文件
右上角--搜索--sign:找到具体js文件,断点调试,查看是什么
发现sign:y(a)不明白这个函数,所以把鼠标放在y上,回出现第二幅图片,然后点击跳转到y函数,一定要打断点才会跳转到y函数

断点调试

image.png

点击后跳到该页面
在y函数附近继续打断点调试,知道function e 传入的参数是搜索的单词,找到该function所属的define

image.png
3.生成sign的y(a)函数具体代码如下(在一个大的define中),把下面的三个function放入node.js文件中
define("translation:widget/translate/input/pGrab", function(r, o, t) {
"use strict";
function a(r) {
if (Array.isArray(r)) {
for (var o = 0, t = Array(r.length); o < r.length; o++)
t[o] = r[o];
return t
}
return Array.from(r)
}
function n(r, o) {
for (var t = 0; t < o.length - 2; t += 3) {
var a = o.charAt(t + 2);
a = a >= "a" ? a.charCodeAt(0) - 87 : Number(a),
a = "+" === o.charAt(t + 1) ? r >>> a : r << a,
r = "+" === o.charAt(t) ? r + a & 4294967295 : r ^ a
}
return r
}
function e(r) {
var o = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
if (null === o) {
var t = r.length;
t > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(t / 2) - 5, 10) + r.substr(-10, 10))
} else {
for (var e = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), C = 0, h = e.length, f = []; h > C; C++)
"" !== e[C] && f.push.apply(f, a(e[C].split(""))),
C !== h - 1 && f.push(o[C]);
var g = f.length;
g > 30 && (r = f.slice(0, 10).join("") + f.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + f.slice(-10).join(""))
}
var u = void 0
, l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
u = null !== i ? i : (i = window[l] || "") || "";
for (var d = u.split("."), m = Number(d[0]) || 0, s = Number(d[1]) || 0, S = [], c = 0, v = 0; v < r.length; v++) {
var A = r.charCodeAt(v);
128 > A ? S[c++] = A : (2048 > A ? S[c++] = A >> 6 | 192 : (55296 === (64512 & A) && v + 1 < r.length && 56320 === (64512 & r.charCodeAt(v + 1)) ? (A = 65536 + ((1023 & A) << 10) + (1023 & r.charCodeAt(++v)),
S[c++] = A >> 18 | 240,
S[c++] = A >> 12 & 63 | 128) : S[c++] = A >> 12 | 224,
S[c++] = A >> 6 & 63 | 128),
S[c++] = 63 & A | 128)
}
for (var p = m, F = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), D = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), b = 0; b < S.length; b++)
p += S[b],
p = n(p, F);
return p = n(p, D),
p ^= s,
0 > p && (p = (2147483647 & p) + 2147483648),
p %= 1e6,
p.toString() + "." + (p ^ m)
}
var i = null;
t.exports = e
});
4.因为不知道function里代码的内容,直接将代码写入本地js文件,利用pyexecjs模块执行js代码进行调试
import execjs
#先把node.js中代码读出来
with open("node.js","r") as f:
js_data = f.read()
#创建对象
exec_obj = execjs.compile(js_data)
sign = exec_obj.eval('e("hello")')
print(sign)
执行代码时报错"execjs._exceptions.ProgramError: TypeError: 'window' 未定义",在node.js中找到window所在的位置。把框里的内容,在console中进行调试,得到结果'gtk',在源码中搜索'gtk'。找到截图中的数字,发现在上面断点调试var u 也是这个值因此,node.js代码进行变更,

image.png

image.png

image.png

image.png
重新运行得到结果。
5.获取token
在js中 token:window.common.token
在响应内容中想办法获取此值
url地址为百度翻译的首页,响应中会有token
token_url = https://fanyi.baidu.com/translate?aldtype=16047
正则表达式:"token: '(.*?)'"
上面为分析过程,下面具体代码实现
import requests
import re
import execjs
class BaiduTranslateSpider(object):
def __init__(self):
self.get_url = "https://fanyi.baidu.com/translate?aldtype=16047"
self.post_url = "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;q=0.9",
"accept-encoding": "gzip, deflate, br",
"accept-language": "zh-CN,zh;q=0.9",
"cache-control": "max-age=0",
"cookie": "BIDUPSID=638226CC08DFEEBBB751C5839A389E19; PSTM=1583642008; BAIDUID=638226CC08DFEEBB49F5C08788771727:FG=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; to_lang_often=%5B%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%2C%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%5D; from_lang_often=%5B%7B%22value%22%3A%22zh%22%2C%22text%22%3A%22%u4E2D%u6587%22%7D%2C%7B%22value%22%3A%22en%22%2C%22text%22%3A%22%u82F1%u8BED%22%7D%5D; BDUSS=jJVdUNoZzFRWkxKYmI2dDdnb0tReVlRTUtmY2F1VGVqUG10b3FYMFBLUkZwNDllRVFBQUFBJCQAAAAAAAAAAAEAAABRYDZx7Pi2qLXE0MS84bPWAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEUaaF5FGmhef; delPer=0; PSINO=1; ZD_ENTRY=baidu; BDRCVFR[5IRyTarJWqT]=mbxnW11j9Dfmh7GuZR8mvqV; BDRCVFR[feWj1Vr5u3D]=I67x6TjHwwYf0; BCLID=9290734974203090545; BDSFRCVID=xJ4OJeC62mBTH37uHo0_Mbbz8_ob8m7TH6aIwt7f69vjWd_7NwPPEG0PoM8g0Ku-hD88ogKK0mOTHUkF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; H_BDCLCKID_SF=JbAtoKD-JKvJfJjkM4rHqR_Lqxby26nOWJn9aJ5nJDoVExbSDTJhy-RQBPca5JIOXKOaVnC5QpP-HqT655Jtj6FBMRJby5bwbaRTKl0MLn7Ybb0xyn_VMM3beMnMBMPjamOnaU5o3fAKftnOM46JehL3346-35543bRTLnLy5KJYMDcnK4-XD6JLDGbP; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1583757418,1583879997,1584257463; BDRCVFR[fb3VbsUruOn]=ddONZc2bo5mfAF9pywdpAqVuNqsus; H_PS_PSSID=; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1584275693; yjs_js_security_passport=6f6ce52f07369f2d631f71c99517bde0fe0e4964_1584275697_js; __yjsv5_shitong=1.0_7_102fc37077601fc60fe8cd18e3527e3266b9_300_1584275697472_111.203.200.203_759a45fa",
"referer": "https://fanyi.baidu.com/translate?aldtype=16047&query=&keyfrom=baidu&smartresult=dict&lang=auto2zh",
"sec-fetch-dest": "document",
"sec-fetch-mode": "navigate",
"sec-fetch-site": "same-origin",
"sec-fetch-user": "?1",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36",
}
#获取token
def get_token(self):
html = requests.get(
url = self.get_url,
headers = self.headers
).text
#正则解析
pattern = re.compile("token: '(.*?)'",re.S)
token = pattern.findall(html)[0]
return token
#获取sign
def get_sign(self,word):
with open("node.js","r") as f:
js_data = f.read()
# 创建对象
exec_obj = execjs.compile(js_data)
sign = exec_obj.eval('e("{}")'.format(word))
return sign
#获取翻译结果
def get_result(self,word,fro,to):
token = self.get_token()
sign = self.get_sign(word)
# 把formdata定义成字典
formdata = {
"from": fro,
"to": to,
"query": word,
"transtype": "realtime",
"simple_means_flag": "3",
"sign": sign,
"token": token,
"domain": "common",
}
html_json = requests.post(
url = self.post_url,
data = formdata,
headers = self.headers
).json()
return html_json
if __name__ == '__main__':
spider = BaiduTranslateSpider()
choice = input("1.翻译英语 2.翻译汉语 请选择(1/2):")
if choice == "1":
fro = "en"
to = "zh"
else:
fro = "zh"
to = "en"
word= input("请输入要翻译的单词:")
result = spider.get_result(word,fro,to)
print(result)