Python爬虫计算sign参数

在构造爬虫请求时,通过浏览器抓包发现请求参数中带了一个sign参数:


抓包

使用requests包构造爬虫请求,发现如果缺少这个sign字段或者sign计算的不正确,则只能得到“invalid signature”的服务端返回结果,无法得到正确的结果。因此还是只能研究一下sign是如何计算出来的。

通过观察sign的字符串大致能够猜到,是用了类似于md5的一种加密计算方式,加密用到的字段可能包括发送的messages,以及发送的“time”时间戳字段。之后,在服务端使用相同加密方式计算哈希值,如果结果一致才能正确返回结果,不一致则会返回错误。

要计算哈希值,肯定这段函数是放在js里的,所以我们在开发者工具中进入到“调试器”,然后全局搜索我们抓包的API路径:


search for api path

这样就能定位到发送请求的那一段js代码,而这段代码中肯定就包含请求中的“sign”字段是从哪个变量取的,之后我们就可以看到“sign”字段的变量是如何被计算出来的。


post params

为了能够实现跳转函数定义,我们可以把整个js文件拷贝到vscode中,然后格式化代码,这样读起来更容易。定位到最终计算哈希值的函数:


sign function

可以看到sign字段是由时间戳+message字段计算的一个SHA256哈希值,为了能在爬虫代码中调用这段函数得到sign字段,我们需要安装一个python第三方库,用于在python代码中执行js函数:

pip install PyExecJS

不过,我们需要先注意到,这段js函数是异步的(async),也就是如果直接调用函数的话,你其实拿不到任何返回值,js中想要获取异步函数的值,都是通过函数执行完成之后的回调实现的,而我们要在python代码中执行js的话,显然是没法回调的。所以我们最佳的办法是不用异步函数,想办法寻找同步函数作为替代。

分析这段js代码可以看到,异步的地方主要在于crypto.subtle包,所以上网一搜,有一个同步的函数也能达到同样的效果,于是我们的js代码就可以变为:

var crypto = require('crypto');
function sha256(content) {  
    // https://stackoverflow.com/questions/57626477/using-javascript-crypto-subtle-in-synchronous-function
    return crypto.createHash('sha256').update(content).digest('hex')
  }

function getSign(t, msg) {
    n = {}.PUBLIC_SECRET_KEY,
    a = `${t}:${msg}:${n}`;
    sign = sha256(a)
    return sign
};

之后,在python代码中调用这段js函数,传入时间戳和message参数,然后获取函数返回结果:

import execjs
import time

js_sha = '''
    var crypto = require('crypto');
    function sha256(content) {
        return crypto.createHash('sha256').update(content).digest('hex')
    }
    function getSign(t, msg) {
        n = {}.PUBLIC_SECRET_KEY,
        a = `${t}:${msg}:${n}`;
        sign = sha256(a)
        return sign
    };
'''
time_now = int(time.time())
msg = "XXXX"
signature = execjs.compile(js_sha).call('getSign', time_now, msg)

之后,在requests请求的表单数据中加入计算得到的sign参数,就能得到服务端的正常返回了。

参考:https://www.bilibili.com/read/cv19971275/

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容