Fork me on GitHub

python爬取百度翻译

通过建议列表爬取

请求分析

打开浏览器开发者工具。随便输入一些文本(这里输入的是”test”)。
会抓取到如下请求:

根据请求的名称可以猜出来:这是获取建议列表的请求。

可以看到,这是一个post请求,参数很简单,只有一个kw参数。

代码编写

那么,代码就很好写了:

1
2
3
4
5
6
7
8
9
10
11
12
13
import requests,json

def fanyi(text):
url = 'https://fanyi.baidu.com/sug'
data = {
'kw': text
}
r = requests.post(url,data=data)
jsonw = json.loads(r.text)
res = jsonw['data'][0]['v']
return res

print(fanyi(input(': ')))

缺点

某些时候并不会显示建议列表(列表为空),此时就无法通过此方式爬取翻译结果。

根据翻译结果请求爬取

除此之外,我们还能找到一个请求,这个应该才是真正的翻译结果:

请求分析

请求参数如下:

请求链接为https://fanyi.baidu.com/v2transapi?from=en&to=zh ,请求方式为POST。

token获取

先从网页源代码入手,我们发现token居然就写在网页源代码里,且与刚才请求中的值一致。

那么,token就轻松解决了。

sign获取

sign是请求的关键参数,类似Google翻译的tk参数。
源代码全局搜索sign,下个断点,找到sign的计算算法。
稍作整理,如下(这里定义的i为一个定值,无需修改):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
var i="320305.131321201";
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)
}

代码编写

使用execjs库,编写python代码如下(经测试,这里的cookie是一定需要的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import execjs,requests,json

def fanyi(text):
url='https://fanyi.baidu.com/v2transapi?from=en&to=zh'
with open('baidusign.js','r',encoding='utf-8') as f: #为了缩减代码长度,这里直接从本地读取js(上面的代码)
js = f.read()
ct=execjs.compile(js)
sign=ct.call('e',text)
#print(sign)
data={
'from':'en', #源语言
'to':'zh', #目标语言
'query':text, #文本
'transtype':'translang',
'simple_means_flag':'3',
'sign':sign,
'token':'8a1fdf7e200b63f79705085127576e17'
}
headers={
'cookie': 'BAIDUID=7130FE0D4F03C5F2254E573B36C9E044:FG=1',
}
r=requests.post(url,data=data,headers=headers)
json_data=json.loads(r.text)
#print(json_data)
res=json_data['trans_result']['data'][0]['dst']
return res

print(fanyi(input(": ")))

cookie直接复制,如下图:

语言代码请参考网页源代码中的langList

1
2
3
langList: {
'zh': '中文','jp': '日语','jpka': '日语假名','th': '泰语','fra': '法语','en': '英语','spa': '西班牙语','kor': '韩语','tr': '土耳其语','vie': '越南语','ms': '马来语','de': '德语','ru': '俄语','ir': '伊朗语','ara': '阿拉伯语','est': '爱沙尼亚语','be': '白俄罗斯语','bul': '保加利亚语','hi': '印地语','is': '冰岛语','pl': '波兰语','fa': '波斯语','dan': '丹麦语','tl': '菲律宾语','fin': '芬兰语','nl': '荷兰语','ca': '加泰罗尼亚语','cs': '捷克语','hr': '克罗地亚语','lv': '拉脱维亚语','lt': '立陶宛语','rom': '罗马尼亚语','af': '南非语','no': '挪威语','pt_BR': '巴西语','pt': '葡萄牙语','swe': '瑞典语','sr': '塞尔维亚语','eo': '世界语','sk': '斯洛伐克语','slo': '斯洛文尼亚语','sw': '斯瓦希里语','uk': '乌克兰语','iw': '希伯来语','el': '希腊语','hu': '匈牙利语','hy': '亚美尼亚语','it': '意大利语','id': '印尼语','sq': '阿尔巴尼亚语','am': '阿姆哈拉语','as': '阿萨姆语','az': '阿塞拜疆语','eu': '巴斯克语','bn': '孟加拉语','bs': '波斯尼亚语','gl': '加利西亚语','ka': '格鲁吉亚语','gu': '古吉拉特语','ha': '豪萨语','ig': '伊博语','iu': '因纽特语','ga': '爱尔兰语','zu': '祖鲁语','kn': '卡纳达语','kk': '哈萨克语','ky': '吉尔吉斯语','lb': '卢森堡语','mk': '马其顿语','mt': '马耳他语','mi': '毛利语','mr': '马拉提语','ne': '尼泊尔语','or': '奥利亚语','pa': '旁遮普语','qu': '凯楚亚语','tn': '塞茨瓦纳语','si': '僧加罗语','ta': '泰米尔语','tt': '塔塔尔语','te': '泰卢固语','ur': '乌尔都语','uz': '乌兹别克语','cy': '威尔士语','yo': '约鲁巴语','yue': '粤语','wyw': '文言文','cht': '中文繁体'
},

至此,就完成了百度翻译结果的爬取。