[Python | 爬虫] 百度翻译(JS逆向获取sign值)

目录

一、问题简介

二、解决方案

 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页面获取;

二、解决方案

 1、全局搜索sign

全局搜索框中输入“sign:”,查看哪个文件中含有“sign:”关键字:

这里出现了三个文件存在”sign:“,那我们就需要对这三个文件都观察,这里直接给出结论:index.239fe7e6.js 就是目标文件(每个人有所不同,但都包含index)

2、文件局部搜索

选中文件内容,按下 Ctrl + F,在文件局部搜索框中输入“sign:”,出现了 7 个结果:

将这 7 个结果全都打上断点,在输入框中输入一些内容后,刷新页面,进入断点调试。

不断恢复脚本执行,直到断点标记处出现了“sign”关键字:

我们发现这个变量 w 包含了前面表单的所有内容,所以它极有可能是我们需要的结果。

再将光标放在变量 w 的前一个变量 e 上,发现 e 是我们输入的内容,那么赋值给 sign 的这个函数b(e),就是计算出sign值的函数

将光标置于 b(e) 上,点击函数链接。(这里的b(e)就是目标函数,陌生环境要将其他的断点处函数一并观察)。

3、寻找目标函数

现在我们跳转到了 b(e) 函数的本体位置,发现光标聚焦在 t.exports = function(t) 上,但是前面的函数是 b(e) 呀,这个 t 是什么呢?

我们可以在这之后打一个断点,然后恢复脚本执行,就可以得到断点之前的变量的值

显然,这个 t 就是 b(e) 中的 e,也就是我们想要翻译的内容,同时 function(t) 就是我们需要的函数

4、调用函数

把这个 JS 代码 Copy 下来,保存到文件中。

那么我们怎么判断这份代码是否可以运行呢?这里我有两种方法:

(1)第一种:接下来会在 python 用到 execjs 这个库执行 JS 代码,所以可以先写一个 demo 测试,调用这个 JS 代码的函数,报错会直接在控制台显示;

(2)第二种:写一个 HTML 代码,链接 JS 代码,在 JS 代码中调用函数,报错会在浏览器的控制台中显示。

5、补全JS代码

上面两种方法种,我选择第二种方法

HTML代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" src="./baidu-trans.js">

    </script>
</head>
<body>

</body>
</html>

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 代码中:

<script>
    // token为空表示第一次访问百度网站服务器端没有收到baiduid cookie,会导致翻译接口校验不通过,通过刷新解决
                    if (!window.common.token) {
                location.reload();
            }
            window.bdstoken = "148128b550fba9d0be7bd767818ab2c1";window.gtk = "320305.131321201";
            </script>

这真是太好了,说明我们可以先用 python 代码爬取到 window.gtk 的值,然后再传输到 JS 代码的函数中,最终的 JS 代码放在文章最后

JS 代码前后的比较:

(1)添加了变量r的声明,添加了函数n()、e();

(2)修改了函数function(t)的参数;

(2)修改了 r 的赋值操作。

6、token的获取

前面的步骤可以得到 sign 的值,但是还有这个 token 是一串意义不明的字符串。

但因为其在不同的翻译输入中的值是一样的,我们猜测其是从 HTML 页面获得的定值,类似 window.gtk。

下面是 token 所在的 HTML 页面的源码:

<script>
window['common'] = {
    
    
    
    token: 'ddedf58ae734754310d0a715973c1729',
    
    /*
        中间内容已删去
    */

// 防止你的网页被iframe嵌入
if(window !== window.top) {
    window.top.location.href = 'https://fanyi.baidu.com/';
}
</script>

三、Python代码

定义了一个简单的 UI 类,一个简单的爬虫逻辑类。

1、UI类

包含一个输入框、文本框、按钮。

按钮链接了点击事件,当点击后,将创建一个爬虫逻辑对象,实现翻译结果的爬取。

2、爬虫逻辑类

(1)__init__()

定义了多个 UA,这是反爬机制的一种。

注意header中的cookie要改成自己在浏览器上使用的。

(2)get_WindowGtk_and_Token()

在HTML页面上获取 window.gtk 和 token 的值。

(3)get_Sign()

将 window,gtk 的值传到 JS 代码的函数中,计算出 sign 的值并返回。

注意自己的JS代码的路径。

(4)translate()

注意单个单词和句子的翻译结果的路径的不同。

四、完整代码

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, 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");
// }

Python代码:


# 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("<script>(.*?)</script>", 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("<KeyRelease>", 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()

# 
  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值