python爬虫模拟百度翻译
案例目的:
通过模拟百度翻译,介绍携带form表单发送post请求以及破解form表单中的加密数据,以及介绍通过pycharm执行js代码。
案例实现功能:
模拟百度翻译,实现中英互译。
爬取过程分析:
找到目标的url,注意,这里的url是指对应的response为翻译结果的url。而非首页的url。如下图:
检查响应结果:
对比翻译不同内容的表单数据,如下图:
对比翻译不同内容对应表单上发生变化的数据,可以发现表单发生变化的数据为:
1.参数query:为要被翻译的内容
2.参数sign:待分析
剩下其他的参数未发生变换,因此在发送请求时,直接复制到form表单即可。
对参数sign进行分析:
在search中搜索sign参数,返现参数sign对应的为函数f(e),将鼠标左键放在函数f(e)上,可以找到函数所在的位置。
点击之后,找到函数f(e)的位置如下:
这里说明一下,如何使用函数f(e)来得到sign参数:
由于sign参数的值为e函数,且js函数定义的逻辑比较复杂,我们可以直接通过在pycharm创建js文件,执行js函数,我们直接使用函数的返回值即可。
经过创建在pycharm创建javascript文件执行e函数,但在执行python代码时发现e函数中缺少参数i和参数n。因此我们需要解决如何得到参数i和n的问题。
首先,找到参数i如下:
经过调试发现,i的值与u的值带相同,且i为定值,因此对于参数i的解决方法为:将在函数e中定义i的中即var i = 320305.131321201
其次,找到参数n所在位置为函数n
点击找到函数n的位置
我们找到函数n,在函数e的上方。
对于参数n的解决方法:将函数n同样复制在javascript文件函数e上方执行。我们直接使用js代码的返回值即可。
解析响应的方法:
通过在线json在分析,对response数据进行解析。得到jsonpath语法($…dst)
注意事项:
1.表单数据中的参数from为zh,参数to为en,意为中译英,而英译中是无法完成的,因此需要通过添加if条件语序。即当输入为英文,翻译成中文。从而完成中英互译
2.我们创建的Javascript文件以及函数f(e),f(n)。需要通过在python代码中打开文件,执行代码后才能获得函数中的返回值,从而得到参数sign。
3.我们可以通过在程序入口处加上while死循环,可以让翻译一直进行,避免手动执行。
4.本次案例为post请求,重在于表单数据参数的解析。
所有问题分析完毕,上代码:
代码一:
代码一为js代码,需要创建JavaScript文件。(注:需要通过在代码二中打开文件,并执行,打开和执行见代码二。从而得到其返回值。)
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 i = "320305.131321201"
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)
}
代码二:
import requests
import execjs
import jsonpath
if __name__ == '__main__':
# 创建死循环,避免手动执行
while True:
# 输入要被翻译的数据
content = input('请输入要被翻译的数据:')
# 确认目标的url
url = 'https://fanyi.baidu.com/v2transapi?from=zh&to=en'
# 构造请求头参数
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36',
'Referer':'https://fanyi.baidu.com/?aldtype=16047',
'Cookie':'BIDUPSID=9B52293DE599F4D47495D0CFA8C224D8; PSTM=1609681670; BAIDUID=9B52293DE599F4D41A2D56C73F767999:FG=1; REALTIME_TRANS_SWITCH=1; FANYI_WORD_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; SOUND_PREFER_SWITCH=1; BAIDUID_BFESS=9B52293DE599F4D41A2D56C73F767999:FG=1; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; H_PS_PSSID=33423_33403_33272_33595_33335_26350; delPer=0; PSINO=2; BA_HECTOR=0k0h8g85ah2424019f1g2l0jq0r; __yjs_duid=1_28c42f6947c2f92fec57e2a737ed56d81613398651643; BCLID=7220913959098656623; BDSFRCVID=Cw-OJexroG3VnUoe2AxkUPrNo_weG7bTDYLtOwXPsp3LGJLVJeC6EG0Pts1-dEu-EHtdogKK0gOTH6KF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; H_BDCLCKID_SF=tR3aQ5rtKRTffjrnhPF33U-3XP6-hnjy3b7pWfKb5CoNVxTa0b5Fhp4Wbttf5q3RymJ42-39LPO2hpRjyxv4y4Ldj4oxJpOJ-bCL0p5aHl51fbbvbURvD--g3-AqBM5dtjTO2bc_5KnlfMQ_bf--QfbQ0hOhqP-jBRIEoCvt-5rDHJTg5DTjhPrMMNORWMT-MTryKKOCaf5oeDoq2MQl0bDNhnnfKx-fKHnRhlR2B-3iV-OxDUvnyxAZyxomtfQxtNRJQKDE5p5hKq5S5-OobUPUDMJ9LUkqW2cdot5yBbc8eIna5hjkbfJBQttjQn3hfIkj2CKLtCvDqTrP-trf5DCShUFsBfKLB2Q-XPoO3KO4DxKRbj5N2-FA0h5w2hRf5mkf3fbgylRp8P3y0bb2DUA1y4vpBtQmJeTxoUJ2-KDVeh5Gqfo15-0ebPRiJPb9Qg-qahQ7tt5W8ncFbT7l5hKpbt-q0x-jLTnhVn0MBCK0hDvPKITD-tFO5eT22-us05kL2hcHMPoosIOKhloobjDF2MRPQnjwaaOf0l05KfbUoqRmXnJi0btQDPvxBf7pWDTm_q5TtUJMqIDzbMohqfLn5MOyKMnitIv9-pPKWhQrh459XP68bTkA5bjZKxtq3mkjbPbDfn028DKu-n5jHjjLeHD83f; BCLID_BFESS=7220913959098656623; BDSFRCVID_BFESS=Cw-OJexroG3VnUoe2AxkUPrNo_weG7bTDYLtOwXPsp3LGJLVJeC6EG0Pts1-dEu-EHtdogKK0gOTH6KF_2uxOjjg8UtVJeC6EG0Ptf8g0M5; H_BDCLCKID_SF_BFESS=tR3aQ5rtKRTffjrnhPF33U-3XP6-hnjy3b7pWfKb5CoNVxTa0b5Fhp4Wbttf5q3RymJ42-39LPO2hpRjyxv4y4Ldj4oxJpOJ-bCL0p5aHl51fbbvbURvD--g3-AqBM5dtjTO2bc_5KnlfMQ_bf--QfbQ0hOhqP-jBRIEoCvt-5rDHJTg5DTjhPrMMNORWMT-MTryKKOCaf5oeDoq2MQl0bDNhnnfKx-fKHnRhlR2B-3iV-OxDUvnyxAZyxomtfQxtNRJQKDE5p5hKq5S5-OobUPUDMJ9LUkqW2cdot5yBbc8eIna5hjkbfJBQttjQn3hfIkj2CKLtCvDqTrP-trf5DCShUFsBfKLB2Q-XPoO3KO4DxKRbj5N2-FA0h5w2hRf5mkf3fbgylRp8P3y0bb2DUA1y4vpBtQmJeTxoUJ2-KDVeh5Gqfo15-0ebPRiJPb9Qg-qahQ7tt5W8ncFbT7l5hKpbt-q0x-jLTnhVn0MBCK0hDvPKITD-tFO5eT22-us05kL2hcHMPoosIOKhloobjDF2MRPQnjwaaOf0l05KfbUoqRmXnJi0btQDPvxBf7pWDTm_q5TtUJMqIDzbMohqfLn5MOyKMnitIv9-pPKWhQrh459XP68bTkA5bjZKxtq3mkjbPbDfn028DKu-n5jHjjLeHD83f; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1611972652,1613398652,1613398710,1613398717; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1613398731; ab_sr=1.0.0_ZmFjMTE1Yzk0NmJjMTQ5ZTIzMGFlNjJlZmZjYzAwYjU5NTJiMGIwNWY1NDYwMmZhM2EzYTFkNjk0YWJjMjUzOTU5NjU0NWRkOWYzY2RhNGJkOWE0MTQyYjg2NmI0ODcy; __yjsv5_shitong=1.0_7_5a18ebaa65e43b880df42784efe7d394376e_300_1613398729990_182.126.76.2_dad823f0'
}
# 打开js_data文件,获取里面的js代码
with open('js_data.js','r')as f:
js_code = f.read()
# 执行函数,得到结果
js_obj = execjs.compile(js_code)
# 指定调用函数,得到返回值
sign_ = js_obj.call('e',content)
# 首先解析表单数据
query = content
form_data1 = {
'from': 'zh',
'to': 'en',
'query': query,
'simple_means_flag': '3',
'sign': sign_,
'token': '726d35b8d4dd6d6a4ba72b1f8e64e9f9',
'domain': 'common'
}
form_data2 = {
'from': 'en',
'to': 'zh',
'query': query,
'simple_means_flag': '3',
'sign': sign_,
'token': '726d35b8d4dd6d6a4ba72b1f8e64e9f9',
'domain': 'common'
}
if content.islower():
form_data = form_data2
else:
form_data = form_data1
# 在发送请求前,加上异常处理操作
try:
# 发送请求,获取数据
response_ = requests.post(url,headers=headers,data=form_data)
# 数据类型为json数据,将数据先转换成python数据
py_data = response_.json()
# 提取翻译出的内容
res_ = jsonpath.jsonpath(py_data,'$..dst')[0]
# 打印翻译出的内容
print('翻译出的内容为:',res_)
except:
print('你的输入有误,请重新输入...')