您的当前位置:首页>全部文章>文章详情

python之js逆向爬虫实战(对加密的结果数据解密)

发表于:2024-07-17 23:11:48浏览:270次TAG: #python #解密 #js逆向

引言

我们在爬取数据的时候经常遇到接口返回的数据是加密的,本文将演示如何对加密结果进行解密

环境

技术点:execjs
模块:execjs

# 安装execjs模块(需梯子)
pip install PyExecJS

适合AES解密/适合接口返回的加密数据
演示站点:https://www.bidcenter.com.cn/
演示接口:https://interface.bidcenter.com.cn/search/GetRelatedDataHandler.ashx
示例:
图片alt

思路

  • 找出解密的JS方法,具体方法参考:https://blog.dazijie.com/article/156
  • 把该JS方法复制到本地JS文件,以便python方法调用(注意:若是该方法调用第三方JS模块,则我们本地也需要安装对应的模块才能调用起来)

    实现

  • 找到解密的JS方法
    图片alt

  • 复制该方法放到本地的js文件,并安装所需的JS模块
    图片alt

  • 找出解密方法的固定变量,KEY,IV等(方法中:variate.key,variate.aceIV)
    图片alt

图片alt

图片alt

  • 完整JS代码
/**
 * 引入模块并赋值给变量
 */
const CryptoJS = require("crypto-js")

const KEY = {
    "words": [
        863652730,
        2036741733,
        1164342596,
        1782662963
    ],
    "sigBytes": 16
}

const IV = {
    "words": [
        1719227713,
        1314533489,
        1397643880,
        1749959510
    ],
    "sigBytes": 16
}
/**
 * AES解密
 * @param {*} str 加密的字符串
 * 这里调用了第三方库“CryptoJS”,安装模块命令:
 * npm install crypto-js
 * @returns 
 */
function AESDecrypt(str) {
    var nContent = CryptoJS.AES.decrypt(str, KEY, {
        iv: IV,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.ZeroPadding
    })
    if (nContent && nContent != null) {
        try {
            var constr = CryptoJS.enc.Utf8.stringify(nContent)
            if (constr != "") {
                var data = JSON.parse(constr);
                return data['other2']['listData'];
            }
            else
                return null;
        }
        catch (err) {
            return null;
        }

    } else {
        return null;
    }

}
  • 使用https://curlconverter.com/快速生成请求方法,完整代码
    这里有个坑,在引入execjs前,必须先引入,否则会报错,估计是版本问题
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')
  • main.py
import requests
import subprocess
from functools import partial
subprocess.Popen = partial(subprocess.Popen, encoding='utf-8')
import execjs

class Spider:
    """
    采集bidcenter
    """
    def __init__(self) -> None:
        self.max_page = 1
        self.page_url = "https://www.bidcenter.com.cn/"
        self.api_url = "https://interface.bidcenter.com.cn/"
        self.limit = 10
        pass

    def start(self):
        """
        入口
        """
        headers = {
            'accept': 'text/plain, */*; q=0.01',
            'accept-language': 'zh-CN,zh;q=0.9',
            'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'origin': 'https://search.bidcenter.com.cn',
            'priority': 'u=1, i',
            'referer': 'https://search.bidcenter.com.cn/',
            'sec-ch-ua': '"Not/A)Brand";v="8", "Chromium";v="126", "Google Chrome";v="126"',
            'sec-ch-ua-mobile': '?0',
            'sec-ch-ua-platform': '"Windows"',
            'sec-fetch-dest': 'empty',
            'sec-fetch-mode': 'cors',
            'sec-fetch-site': 'same-site',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
        }

        # keywords = input("请输入关键字:")
        keywords = "服务器"

        for x in range(self.max_page):

            data = {
                'from': '6137',
                'guid': 'd124a51f-275f-407c-8448-0f6868899ad6',
                'location': '6138',
                'token': '',
                'next_token': '',
                'keywords': keywords,
                'mod': '0',
                'page': str(x+1),
            }
            response = requests.post(f'{self.api_url}search/GetSearchProHandler.ashx', headers=headers, data=data)
            if response.status_code == 200:
                mylist = self.mydecrypt(response.text)
                print(mylist)
            else:
                print("请求失败")

        pass

    def mydecrypt(self,encrypt_data):
        """
        执行JS文件
        """
        with open("./my.js","r",encoding="utf-8") as f:
            # js_code 就是my.js中的代码
            js_code = f.read()

        # 把 js_code 转成能在python中执行的代码
        ctx = execjs.compile(js_code)
        # 调用AESDecrypt方法,并传入参数encrypt_data
        return ctx.call("AESDecrypt",encrypt_data)

if __name__ == "__main__":
    spider = Spider()
    spider.start()