python 百度翻译爬虫(可翻译句子及文章)
声明
:本文仅限爬虫学习
,不得将本文代码商用
,侵权删
- 如果喜欢本文的话,可不可以给我
点个关注
,点个赞
,评论 + 收藏
(☆▽☆)
创作背景
- 本菜鸡最近要整个
批量翻译词组和句子
,准备调用 百度翻译 的接口,以前也搞过,用的 这个接口,但是只能 翻译单词 ,没法满足需求,所以就需要重新搞。 - 其实以前我就对 这个接口 念念不忘,但是因为当时啥也不会(虽然现在也是),为了图省事儿就没搞,今天
必须拿下
!!!
思路讲解
本文 js 逆向
参考 这个大佬的这篇文章 。
第一步 寻找接口
无非是 按 F12 打开开发者工具
,寻找对应的接口
,具体情况在此不多赘述。
第二步 查看参数
该请求是 POST
请求。
其中
from
参数是源语言
,即 被翻译的文本的语言 ;to
参数是目标语言
,即 要翻译成的语言 ;query
参数是要翻译的文本
;transtype
参数是翻译类型
,置为translang
即可;simple_means_flag
参数不知道干啥,不用管,置为3
即可;sign
参数是标志
,代表要翻译的内容的标志号
,生成方法见后续;token
参数是记号
,每次请求网页源码都会携带token
,见下图;
domain
也不用管,置为common
即可。
第三步 构造 sign
因为 sign
参数是根据 要翻译的文本
生成的,不同的内容对应不同的 sign
,所以我们需要找到生成 sign
的方法。
1. 找到生成 sign
的文件
这时,我们需要使用 全局搜索 查找生成 sign
的地方,如下图。
- 每个文件大致看一遍,我就确认了
sign
生成的函数在 这个文件 中。- 这个文件地址和上述博主文章中的地址不太一样,是因为我想根据我自身的情况实际实践一下,当然,也可以直接使用博主文章中的地址,如果你想看看自己本地的文件,去找
https://fanyi-cdn.cdn.bcebos.com/static/translation/pkg
这个文件夹,我用的 火狐 ,在 调试器 中可以找到
- 然后找到图中的的文件,文件名取决于
全局搜索
的结果,我的结果是这个,至此,这一步结束。
- 这个文件地址和上述博主文章中的地址不太一样,是因为我想根据我自身的情况实际实践一下,当然,也可以直接使用博主文章中的地址,如果你想看看自己本地的文件,去找
2. 找到生成 sign
的函数
上一步 copy 完代码后,我放入 Pycharm
中分析,当然,也可以放到其他编辑器中。
这时,还是 全局搜索 sign
,会搜索出很多 assign
或者 signal
,所以我们需要甄别一下,甄别过后,包含有 sign
的地方有 四 处,如下图。
根据图中代码我们很好判别,第一张 和 第二张 图属于一类,代码逻辑相似,第三张图 和 第四张图 类似,所以我们就分析 第一张 和 第三张 的代码。
第一张图片
在 Pycharm
编辑器中,我们按住 ctrl
点击 d
(因为这时候 sign
是根据 d
生成的),我们就跳转到 d
定义的位置了。
可以看见,是根据函数 n
传参 s
得到,而 s
是函数 t
传参一大堆生成,点击 t
的话,如下图。
是 匿名函数 的参数,如果全局搜索 传递给函数 t
的一大堆的参数 的话也发现不了什么,所以,这条线索 断了 。
第二张图片
我们同样是点击 L
,就跳转到了 L
的生成位置,如下图。
这时我们再搜索函数 t
的参数,如下图。
这时我们会发现有这个模块的定义,其中,define
函数的解释请见 这篇文章 。
说明,模块 translation:widget/translate/input/pGrab
即为生成 sign
的模块。也 符合上述博主的文章
。
3. 分析生成 sign
的函数
通过分析源码,我们可以了解代码逻辑,其中,u
是最终生成 sign
的关键。
不过有个问题,我们看 u
的生成方法:
u = null !== i ? i : (i = window[l] || "") || "";
其中,i
很好得到,因为这个函数下边有 i
的定义:
var i = null;
这样的话,那按照代码逻辑,上边 u
的定义应该是这样:
u = (i = window[l] || "") || "";
这时候,关键就在于参数 l
,l
的定义在上一句:
var u = void 0, l = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
l
是个字符串,通过 console.log()
输出一下 l
的值,是
- 对了,插一句,在
Pycharm
中运行js
代码应该安装Nodejs
,稍后我会专门写一篇文章。
我们在Pycharm
中无法查看window
的值,所以我们就在浏览器的控制台输入window
,查看它的值:
诶,还真被我找到了值,那我们就可以把这个值赋给i
,这样u
直接就是i
,也就是图中的数据。
4. 使用生成 sign
的函数
既然只有这个函数是对我们来说有用的,那就把它 copy 到一个 js 文件中,使用 python 的第三方库 execjs
执行 js 代码,即:
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(/[�-�][�-�]/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(/[�-�][�-�]/), 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);
console.log("l:", l);
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
测试,测试代码如下:
import execjs
with open('sign.js', encoding='utf-8') as f:
js_code = f.read()
create_sign = execjs.compile(js_code)
print(create_sign.call('e', 'year'))
成功!!!
第四步 进行翻译
请求的时候有 反爬,所以 Cookie
和 User-Agent
一个都不能少,代码如下:
import json
import execjs
import requests
with open('sign.js', encoding='utf-8') as f:
js_code = f.read()
create_sign = execjs.compile(js_code)
def translate(kw):
data = {
'from': 'en',
'to': 'zh',
'query': kw,
'transtype': 'translang',
'simple_means_flag': 3,
'sign': create_sign.call('e', kw),
'token': '【用自己的】',
'domain': 'common'
}
headers = {
'Cookie': '【用自己的,别想白嫖我的】',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:80.0) Gecko/20100101 Firefox/80.0'
}
res = requests.post('https://fanyi.baidu.com/v2transapi?from=en&to=zh', data=data, headers=headers)
print(res.json())
translate('year')
结果如下:
特别多,我们只要想要的数据,一般是 data
列表中的 第一个数据 :
print(res.json()['trans_result']['data'][0])
结果如下:
成功完成任务!!!
一些问题的解决
总结
这是本菜鸡 第一次
成功的完成 js 逆向
,逆向
之路,道阻且跻,但我仍要不断前行。
结尾
有想要一起学习 python
的小伙伴可以 私信我
进群哦。
以上就是我要分享的内容,因为学识尚浅,会有不足,还请各位大佬指正。
有什么问题也可在评论区留言。