目录
一、问题简介
二、解决方案
1、全局搜索sign
2、文件局部搜索
3、寻找目标函数
4、调用函数
5、补全JS代码
6、token的获取
三、Python代码
1、UI类
2、爬虫逻辑类
四、完整代码
JS代码:
Python代码:
相信大家在学习爬虫的过程中都试图写一个翻译的爬虫,那么百度翻译就会是一个练习的目标。
那么我个人在尝试过程中,发现了一鞋问题:
1、当确定翻译结果是通过ajax请求得到的之后,我误以为是通过对下面这个 URL 发送请求:
https://fanyi.baidu.com/sug
2、后来发现这个 url 只能做到翻译一个单词,不能翻译一段话。
3、观察其他的 XHR 请求之后,发现了下面这个 URL 才是能够翻译句子的:
https://fanyi.baidu.com/v2transapi?from=en&to=zh
4、观察这个 URL 的请求标头(requests headers),我们能得到一些信息:
(1)其中只有 sign 和 ts 的值是随机变化的,其中 ts 每次翻译都不一样,推测是时间戳,而 sign 的值在相同的 query 下是一样的,不同的 query 会有不同的 sign 值,因此,sign 的值就是其中的重点;
(2)其他的值要么是用户输入,要么是从html页面获取;
在全局搜索框中输入“sign:”,查看哪个文件中含有“sign:”关键字:
这里出现了三个文件存在”sign:“,那我们就需要对这三个文件都观察,这里直接给出结论:index.239fe7e6.js 就是目标文件(每个人有所不同,但都包含index)。
选中文件内容,按下 Ctrl + F,在文件局部搜索框中输入“sign:”,出现了 7 个结果:
将这 7 个结果全都打上断点,在输入框中输入一些内容后,刷新页面,进入断点调试。
不断恢复脚本执行,直到断点标记处出现了“sign”关键字:
我们发现这个变量 w 包含了前面表单的所有内容,所以它极有可能是我们需要的结果。
再将光标放在变量 w 的前一个变量 e 上,发现 e 是我们输入的内容,那么赋值给 sign 的这个函数b(e),就是计算出sign值的函数。
将光标置于 b(e) 上,点击函数链接。(这里的b(e)就是目标函数,陌生环境要将其他的断点处函数一并观察)。
现在我们跳转到了 b(e) 函数的本体位置,发现光标聚焦在 t.exports = function(t) 上,但是前面的函数是 b(e) 呀,这个 t 是什么呢?
我们可以在这之后打一个断点,然后恢复脚本执行,就可以得到断点之前的变量的值:
显然,这个 t 就是 b(e) 中的 e,也就是我们想要翻译的内容,同时 function(t) 就是我们需要的函数。
把这个 JS 代码 Copy 下来,保存到文件中。
那么我们怎么判断这份代码是否可以运行呢?这里我有两种方法:
(1)第一种:接下来会在 python 用到 execjs 这个库执行 JS 代码,所以可以先写一个 demo 测试,调用这个 JS 代码的函数,报错会直接在控制台显示;
(2)第二种:写一个 HTML 代码,链接 JS 代码,在 JS 代码中调用函数,报错会在浏览器的控制台中显示。
上面两种方法种,我选择第二种方法:
HTML代码:
Title
JS代码:
window.onload = function() { // 用html测试时需要加上,当引入python时删掉
function getSign(t) {
var o, i = t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
if (null === i) {
var a = t.length;
a > 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
} else {
for (var s = t.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), c = 0, u = s.length, l = []; c < u; c++)
"" !== s[c] && l.push.apply(l, function(t) {
if (Array.isArray(t))
return e(t)
}(o = s[c].split("")) || function(t) {
if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"])
return Array.from(t)
}(o) || function(t, n) {
if (t) {
if ("string" == typeof t)
return e(t, n);
var r = Object.prototype.toString.call(t).slice(8, -1);
return "Object" === r && t.constructor && (r = t.constructor.name),
"Map" === r || "Set" === r ? Array.from(t) : "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ? e(t, n) : void 0
}
}(o) || function() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
}()),
c !== u - 1 && l.push(i[c]);
var p = l.length;
p > 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
}
for (var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107)), h = (null !== r ? r : (r = window[d] || "") || "").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v < t.length; v++) {
var _ = t.charCodeAt(v);
_ < 128 ? g[y++] = _ : (_ < 2048 ? g[y++] = _ >> 6 | 192 : (55296 == (64512 & _) && v + 1 < t.length && 56320 == (64512 & t.charCodeAt(v + 1)) ? (_ = 65536 + ((1023 & _) << 10) + (1023 & t.charCodeAt(++v)),
g[y++] = _ >> 18 | 240,
g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
g[y++] = _ >> 6 & 63 | 128),
g[y++] = 63 & _ | 128)
}
for (var b = f, w = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(97)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(54)), k = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(51)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(98)) + "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(102)), x = 0; x < g.length; x++)
b = n(b += g[x], w);
return b = n(b, k),
(b ^= m) < 0 && (b = 2147483648 + (2147483647 & b)),
"".concat((b %= 1e6).toString(), ".").concat(b ^ f)
}
alert(getSign("i like apple"))
}
(1)运行 HTML 文件后,观察浏览器控制台输出:
控制台显示 r is not defined,因此我们按照断点处样子,加上 var r = null。同理,接下来会出现函数 n() 未定义、变量 r 的值未定义。
对于函数 n() 未定义,我们直接将前面的两个函数 e(t, e)、n(t, e) 也 Copy 下来,这样 JS 代码就变成了:
window.onload = function() { // 用html测试时需要加上,当引入python时删掉
function e(t, e) {
(null == e || e > t.length) && (e = t.length);
for (var n = 0, r = new Array(e); n < e; n++)
r[n] = t[n];
return r
}
function n(t, e) {
for (var n = 0; n < e.length - 2; n += 3) {
var r = e.charAt(n + 2);
r = "a" <= r ? r.charCodeAt(0) - 87 : Number(r),
r = "+" === e.charAt(n + 1) ? t >>> r : t << r,
t = "+" === e.charAt(n) ? t + r & 4294967295 : t ^ r
}
return t
}
var r = null;
function getSign(t) {
var o, i = t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
if (null === i) {
var a = t.length;
a > 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
} else {
for (var s = t.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), c = 0, u = s.length, l = []; c < u; c++)
"" !== s[c] && l.push.apply(l, function(t) {
if (Array.isArray(t))
return e(t)
}(o = s[c].split("")) || function(t) {
if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"])
return Array.from(t)
}(o) || function(t, n) {
if (t) {
if ("string" == typeof t)
return e(t, n);
var r = Object.prototype.toString.call(t).slice(8, -1);
return "Object" === r && t.constructor && (r = t.constructor.name),
"Map" === r || "Set" === r ? Array.from(t) : "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ? e(t, n) : void 0
}
}(o) || function() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
}()),
c !== u - 1 && l.push(i[c]);
var p = l.length;
p > 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
}
for (var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107)), h = (null !== r ? r : (r = window[d] || "") || "").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v < t.length; v++) {
var _ = t.charCodeAt(v);
_ < 128 ? g[y++] = _ : (_ < 2048 ? g[y++] = _ >> 6 | 192 : (55296 == (64512 & _) && v + 1 < t.length && 56320 == (64512 & t.charCodeAt(v + 1)) ? (_ = 65536 + ((1023 & _) << 10) + (1023 & t.charCodeAt(++v)),
g[y++] = _ >> 18 | 240,
g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
g[y++] = _ >> 6 & 63 | 128),
g[y++] = 63 & _ | 128)
}
for (var b = f, w = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(97)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(54)), k = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(51)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(98)) + "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(102)), x = 0; x < g.length; x++)
b = n(b += g[x], w);
return b = n(b, k),
(b ^= m) < 0 && (b = 2147483648 + (2147483647 & b)),
"".concat((b %= 1e6).toString(), ".").concat(b ^ f)
}
alert(getSign("i like apple"))
}
(2)这时候我们运行 HTML 代码,发现已经可以得到一串字符串了,并且格式与sign得一样,可是当我们拿去与表单上的sign值对比,会发现是错误的。
问题就在于这:
h = (null !== r ? r : (r = window[d] || "") || "").split(".")
一开始 r 的值是 null,那么在此判断后,就会将 window[d] 的值赋值给 r。可是 window[d] 在前面并没有被定义,因此又是一个 undefined,就导致了最后的结果出错。
(3)那么怎么解决呢?
这时候我们可以先看看正常情况下的 r 的值是多少,给它打一个断点:
我们发现 r 是一个定值,那么显然 window[d] 也是一个定值。
我们首先看这个 d 的值,d 就在这条赋值语句的前面:
var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107))
103、116、107 其实分别是 g、t、k 这三个字符的 ASCII 码值,也就是说,d = "gtk",因此,window["gtk"] = "320305.131321201"。
其实这个时候我们将其写死在 JS 代码中,就已经完成任务了,但如果以后 window["gtk"] 的值改了呢?那还得我们自己动手去修改 JS 代码,实在不方便,因此我们可以考虑能不能把这个常量找出来。
(4)那么要怎么找到 window[gtk] 的值呢?
我们首先在当前断点调试的 JS 文件中局部搜索,发现关键字 gtk 根本没有,关键字 window 有 tm 二百多个,这肯定不能暴力啊。
于是我们进行全局搜索,发现 gtk 出现在了 HTML 代码中:
这真是太好了,说明我们可以先用 python 代码爬取到 window.gtk 的值,然后再传输到 JS 代码的函数中,最终的 JS 代码放在文章最后:
JS 代码前后的比较:
(1)添加了变量r的声明,添加了函数n()、e();
(2)修改了函数function(t)的参数;
(2)修改了 r 的赋值操作。
前面的步骤可以得到 sign 的值,但是还有这个 token 是一串意义不明的字符串。
但因为其在不同的翻译输入中的值是一样的,我们猜测其是从 HTML 页面获得的定值,类似 window.gtk。
下面是 token 所在的 HTML 页面的源码:
定义了一个简单的 UI 类,一个简单的爬虫逻辑类。
包含一个输入框、文本框、按钮。
按钮链接了点击事件,当点击后,将创建一个爬虫逻辑对象,实现翻译结果的爬取。
(1)__init__()
定义了多个 UA,这是反爬机制的一种。
注意header中的cookie要改成自己在浏览器上使用的。
(2)get_WindowGtk_and_Token()
在HTML页面上获取 window.gtk 和 token 的值。
(3)get_Sign()
将 window,gtk 的值传到 JS 代码的函数中,计算出 sign 的值并返回。
注意自己的JS代码的路径。
(4)translate()
注意单个单词和句子的翻译结果的路径的不同。
// window.onload = function() { // 用html测试时需要加上,当引入python时可以删掉
function e(t, e) {
(null == e || e > t.length) && (e = t.length);
for (var n = 0, r = new Array(e); n < e; n++)
r[n] = t[n];
return r
}
function n(t, e) {
for (var n = 0; n < e.length - 2; n += 3) {
var r = e.charAt(n + 2);
r = "a" <= r ? r.charCodeAt(0) - 87 : Number(r),
r = "+" === e.charAt(n + 1) ? t >>> r : t << r,
t = "+" === e.charAt(n) ? t + r & 4294967295 : t ^ r
}
return t
}
var r = null;
function getSign(t, window_gtk) {
var r = null;
var o, i = t.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
if (null === i) {
var a = t.length;
a > 30 && (t = "".concat(t.substr(0, 10)).concat(t.substr(Math.floor(a / 2) - 5, 10)).concat(t.substr(-10, 10)))
} else {
for (var s = t.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), c = 0, u = s.length, l = []; c < u; c++)
"" !== s[c] && l.push.apply(l, function(t) {
if (Array.isArray(t))
return e(t)
}(o = s[c].split("")) || function(t) {
if ("undefined" != typeof Symbol && null != t[Symbol.iterator] || null != t["@@iterator"])
return Array.from(t)
}(o) || function(t, n) {
if (t) {
if ("string" == typeof t)
return e(t, n);
var r = Object.prototype.toString.call(t).slice(8, -1);
return "Object" === r && t.constructor && (r = t.constructor.name),
"Map" === r || "Set" === r ? Array.from(t) : "Arguments" === r || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r) ? e(t, n) : void 0
}
}(o) || function() {
throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")
}()),
c !== u - 1 && l.push(i[c]);
var p = l.length;
p > 30 && (t = l.slice(0, 10).join("") + l.slice(Math.floor(p / 2) - 5, Math.floor(p / 2) + 5).join("") + l.slice(-10).join(""))
}
// var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107))
for (var d = "".concat(String.fromCharCode(103)).concat(String.fromCharCode(116)).concat(String.fromCharCode(107)), h = (null !== r ? r : (r = window_gtk /* 改为window_gtk */ || "") || "").split("."), f = Number(h[0]) || 0, m = Number(h[1]) || 0, g = [], y = 0, v = 0; v < t.length; v++) {
var _ = t.charCodeAt(v);
_ < 128 ? g[y++] = _ : (_ < 2048 ? g[y++] = _ >> 6 | 192 : (55296 == (64512 & _) && v + 1 < t.length && 56320 == (64512 & t.charCodeAt(v + 1)) ? (_ = 65536 + ((1023 & _) << 10) + (1023 & t.charCodeAt(++v)),
g[y++] = _ >> 18 | 240,
g[y++] = _ >> 12 & 63 | 128) : g[y++] = _ >> 12 | 224,
g[y++] = _ >> 6 & 63 | 128),
g[y++] = 63 & _ | 128)
}
for (var b = f, w = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(97)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(54)), k = "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(51)) + "".concat(String.fromCharCode(94)).concat(String.fromCharCode(43)).concat(String.fromCharCode(98)) + "".concat(String.fromCharCode(43)).concat(String.fromCharCode(45)).concat(String.fromCharCode(102)), x = 0; x < g.length; x++)
b = n(b += g[x], w);
return b = n(b, k),
(b ^= m) < 0 && (b = 2147483648 + (2147483647 & b)),
"".concat((b %= 1e6).toString(), ".").concat(b ^ f)
}
// 输出测试
var result = getSign("i like apple", "123.123");
// }
# ui
import tkinter
import tkinter.font
# 爬虫
import requests
import re
import execjs
# 其他
import random
import time
class Logic_BaiduSpider(object):
def __init__(self, input_data):
# 翻译结果存在的url
self.form_url = 'https://fanyi.baidu.com/v2transapi?from=en&to=zh'
user_agents = ['Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',
'Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1',
'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko)',
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.188']
self.header = {
'cookie': '__yjs_duid=1_674911807aeb99a64bd42a9c8b981be81635202045938; BDUSS=jVOUVJ5UzVHYm5RLTZOcXQwMTlnYUh6R2xkOXpuNnVGSDZ5cVJDOHJsamJJNkpoRVFBQUFBJCQAAAAAAAAAAAEAAAAxky3Otqu3vbrsvrTAz9S6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANuWemHblnphU; BDUSS_BFESS=jVOUVJ5UzVHYm5RLTZOcXQwMTlnYUh6R2xkOXpuNnVGSDZ5cVJDOHJsamJJNkpoRVFBQUFBJCQAAAAAAAAAAAEAAAAxky3Otqu3vbrsvrTAz9S6AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANuWemHblnphU; BIDUPSID=20A7A480A559295EE6B79E9177E7CB49; PSTM=1636242361; REALTIME_TRANS_SWITCH=1; HISTORY_SWITCH=1; SOUND_SPD_SWITCH=1; FANYI_WORD_SWITCH=1; SOUND_PREFER_SWITCH=1; ZFY=1:A:AGMUxBbGCY3losh7kUruzIglNWlYdh1Xp2l07QsbU:C; __bid_n=184357c5337c82193f4207; BAIDU_WISE_UID=wapp_1678495157915_916; FPTOKEN=AprdIvLEU9bU4XXMVm2db8fvIxpW/caHG5gIQcOmzzSKJ2tkUQOhukAMEaXTSw8i1pIsmbcHSXd+KuM6Fvln3K6S1ulFUeneuAd2BOW49c0e/ovKelxFgmeZfzUK90OIQlcuCtSO2HgEVNsbq+0kn9Ip0aUswiejuNsMHjaMTNnb93IuDF6APFdYbOCIbxKkDLWGjf3XcpWhpnAsDK3+j5eb+MUuhFeQk4TMrUfoaLReaTyDkcLefpCFpOUc+/G698uU6/tRq9aG/noenrxIubFfwj1xCT3qXoyfPrI8TTpF/uWelM6uchrSjp5hPd3SdsKcjcz4m04cCdBoPhbA15m/pXArbqf8fhMZAw1PRmaH7ZIm/fvNzFTUwSyQW9rleFsvv5skEugEB4AfsDVdww==|/ZKheBQe/vVpFZKqAJ0btWcOxxJw/SXD/xQ0UtxXePs=|10|4c88b6a1deb83d4e7a67b690c46f7f76; BAIDUID=F8A3226E1FE8708108AE17228963E1E5:FG=1; BAIDUID_BFESS=F8A3226E1FE8708108AE17228963E1E5:FG=1; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1691377121,1691457865,1691481204; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1691481213; ab_sr=1.0.1_MTdhOTRlN2Y4ZGQzYWE3ZDUxNjliMjA5OTBkYmMyNWQwODQ4ODk1MmY0ZjIzN2M1ODJhZWNkMTYyYWY5NTdhNmJmYzcxNTVhMzdkZGE4YzUzMzgxNzA2MDk4NDNjZDQ5YThlMTkxYmQyYjFmNmNkYTU1M2NlYzkyZTQwOWJmZjdlMWQzNGE4OTUwMmY3MzcxNGNjOTJkMmM0ZGEzYjczMjFiYzE1OTk0NWZlZmQxYmExNmI1YmI5MGMxNmUwZjg1',
'user-agent': random.choice(user_agents),
'Referer': 'https://fanyi.baidu.com/',
'Host': 'fanyi.baidu.com',
'Sec-Ch-Ua': '"Not/A)Brand";v="99", "Microsoft Edge";v="115", "Chromium";v="115"',
'Sec-Ch-Ua-Mobile': '?0',
'Sec-Ch-Ua-Platform': '"Windows"',
'Sec-Fetch-Dest': 'empty',
'Sec-Fetch-Mode': 'cors',
'Sec-Fetch-Site': 'same-origin',
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'en-US,en;q=0.9',
'Acs-Token': '1691481214316_1691481256005_/DBI7uAea2WMqgnHYTjOamrbCNblUgG8hE7zhBGZWrYBBSksm7aPbhvjrehrIgt0EhBIDDM9SCxqnM11X4Ik4g4Ha1Etk/DvZmp897QRXb0XVD2jAClg2VlrkKLoFysvXtRsEcbicLwgGKdyOcKzIFf6EXnEV5zjNXtUmQ+BUvV9WyRUS7c5Zdq0XwSl6QN6vIfeJchPqxWhj7GrUcE7xKlDZJeULVtoax4SipcmMYRcLGl3QfIce9SUxtuAptlr0wvPp/4/K7KecJUL2AXnIjKlji4G/9SkJorsOGd0HR3CzT1394o9OP+dUeDzWEUDvgob2xCmJjJjYSjwIP+vwm2Bvj83wIdF4Low+yTTc/snIOhKoUmbkF3bdZ5cm9ht+duquTm2dLZpdAiUWaj+FzIh20eC2nKYcKb4scH1+QhL7g8WtJTjKoq8LmCknVECYVmV5xaL7Qbdt/LmlGL6/lvy/j658dQO5cU6vMfHGmvgoQge2u9Meuc59kHwxWPAXocKoaYSE92RgOHH6sTwoA==',
'Cache-Control': 'no-cache',
}
self.proxies = {
}
self.input_data = input_data
def get_WindowGtk_and_Token(self):
# 获取token和window_gtk用的url
html_url = 'https://fanyi.baidu.com/'
html_text = requests.get(url = html_url, headers = self.header, proxies = self.proxies).text
# 正则数据解析
# res = re.findall("", html_text, re.S)
# print(res[5])
gtk = re.findall('window.gtk = "(.*?)";', html_text, re.S)[0]
token = re.findall('token: \'(.*?)\',', html_text, re.S)[0]
return gtk, token
def get_Sign(self):
with open('D:/Programming Project/PythonProject/Crawler/js/baidu-trans.js', 'r', encoding = "utf-8") as fp:
js_code = fp.read()
js_obj = execjs.compile(js_code)
gtk, token = self.get_WindowGtk_and_Token()
res = 'getSign("{0}", "{1}")'.format(self.input_data, gtk)
sign = js_obj.eval(res)
return sign
def translate(self):
gtk, token = self.get_WindowGtk_and_Token()
print(gtk, token)
param = {
'from': 'en',
'to': 'zh',
'query': self.input_data,
'transtype': 'realtime',
'simple_means_flag': '3',
'sign': self.get_Sign(),
'token': token,
'domain': 'common',
}
html_json = requests.post(url = self.form_url, headers = self.header, data = param, proxies = self.proxies).json()
print(html_json)
if ' ' in self.input_data:
res_singleMean = html_json['trans_result']['data'][0]['dst'] # 这是单个翻译结果
return res_singleMean, 'sentence'
else:
res_list = html_json['dict_result']['simple_means']['word_means']
return res_list, 'word'
class Ui_BaiduSpider(object):
def __init__(self):
self.root = tkinter.Tk()
self.root.title('百度翻译')
self.root.resizable(0, 0) # 设置窗口大小不可变
#root.geometry("440x400+600+300") # width * height + 水平偏移 + 垂直偏移
for i in range(2):
self.root.columnconfigure(i, minsize = 50, pad = 100)
if i == 0:
self.root.rowconfigure(i, minsize = 30, pad = 40)
else:
self.root.rowconfigure(i, minsize = 30, pad = 50)
# label
self.label1 = tkinter.Label(self.root, text = "输入:", font = ("宋体", 24), fg = "black")
self.label1.grid(row = 0, column = 0, sticky = tkinter.W + tkinter.E + tkinter.N + tkinter.S)
# entry
self.input_data = tkinter.StringVar() # 使输入框内容可变
self.entry1 = tkinter.Entry(self.root, font = ("宋体", 24), textvariable = self.input_data)
# entry1.bind("", ButtonAction) # ButtonAction()绑定键盘
self.entry1.grid(row = 0, column = 1, sticky = tkinter.W)
# text
self.text1 = tkinter.Text(self.root)
self.text1.grid(row = 1, columnspan = 2)
# button
self.button = tkinter.Button(self.root, text = "翻译", font = ("宋体", 24), command = self.ButtonAction)
self.button.grid(row = 0, column = 2, pady = 10, padx = 10)
def ButtonAction(self): # 使用entry的key release时,参数要用event,即def function(event)
data = self.entry1.get().strip() # 获取输入框内容
print(data)
if len(data) == 0:
return
spider = Logic_BaiduSpider(data)
trans_results, trans_type = spider.translate()
if trans_type == 'sentence':
self.text1.delete(1.0, tkinter.END)
self.text1.insert(1.0, trans_results)
elif trans_type == 'word':
self.text1.delete(1.0, tkinter.END)
for i in range(len(trans_results)):
self.text1.insert(i + 1.0, '(' + str(i + 1) + ')' + trans_results[i] + "\n")
# text行从1开始,所以在 i + 1.0 行插入
def run(self):
self.root.mainloop() # 运行窗口
if __name__ == "__main__":
ui = Ui_BaiduSpider()
ui.run()
#