最近简单学习了一下 requests 这个模块,一直没有亲自实战一下,然后就有了这次的实战练习

浏览器F12对百度翻译进行抓包

随便输入一个词句抓包

我们主要要获取这里的数据

image-20220226165826866

而这里的数据是对https://fanyi.baidu.com/v2transapi?from=zh&to=en这个链接发起的一次post请求

可以看到请求表单中发送的关键数据

image-20220226170042047

尝试其他词句发现主要变化的是sign,还有token这两个关键变量

在当前页面审查元素就能发现这个token

image-20220226170403142

现在关键是这个sign

查看一下这个post方法的请求栈

image-20220226171701647

主要是index和public这两个js文件,打开搜索一下payload中的sign,发现在index这个js文件里有这个payload

image-20220226172024588

可以发现这里和post表单中的数据格式一样

image-20220226172112996

现在看看这个sign它是怎么生成的

sign: L(e)这里打一个断点调试一下

刷新页面,来到这个sign处,然后点击单步调试

image-20220226172641559

然后跳转到了e(r)这个函数,这个应该就是生成sign的函数

image-20220226172850285

同时发现传递的参数正好是你输入的词句

那么继续单步调试,到函数的末尾发现又调用了一个n(r, o)函数

image-20220226173640837

继续运行,结束

经过上面的调试发现,这个sign就是使用了上面两个函数对输入的词句进行加密操作,具体的算法比较复杂,不需要搞懂它,我们可以使用python中的execujs这个库来运行,这个js代码,得到加密后的sign

先不要急,在浏览器跑一下这个加密代码

cv到控制台,输入参数运行

image-20220226174341838

发现报错了,查看报错列表知道是 i 这个变量没有定义

那么继续回到原来的调试

找到这个变量 i ,打个断点

image-20220226174645619

运行,发现这个变量 i 的值为 320305.131321201

image-20220226174857744

改变输入的词句发现这个 i 始终是个定值,都是 320305.131321201 ,那么现在所有的问题基本上就解决了,

剩下的就是写爬虫脚本,代码如下

对应 sign 的js代码

i = '320305.131321201';

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 %= 1000000,
    p.toString() + '.' + (p ^ m)
  }

python脚本

import execjs
import requests
import re
import json
mainUrl = 'https://fanyi.baidu.com'
trsUrl = 'https://fanyi.baidu.com/v2transapi'

with open('sign.js', 'r') as file:# sign.js从浏览器对应的文件中复制过来
    jsCode = file.read()

session = requests.session()
indexResp = session.get(mainUrl)
token = re.findall("token: '(.*?)'", indexResp.text)[0]

def translate(word):
    data = {
        # 这里将from和to参数改为auto发现可以任意语言翻译为中文,中文翻译为英文,可自动切换
        "from": "auto",
        "to": "auto",
        "query": word,
        "transtype": "realtime",
        "simple_means_flag": "3",
        "sign": execjs.compile(jsCode).call('e', word),
        "token": token,
        "domain": "common"
    }
    return session.post(trsUrl, data=data).text
if __name__ == '__main__':
    word = input('请输入要翻译的词句: ')
    response = translate(word)
    print(json.loads(response)['trans_result']['data'][0]['dst'])

最后测试,中英文都没问题

image-20220226180017204

image-20220226180043589