爬虫案例:建设库JS逆向

news2024/12/26 7:10:15

爬虫流程

1. 确定目标网址和所需内容

https://www.jiansheku.com/search/enterprise/

只是个学习案例,所以目标就有我自己来选择,企业名称,法定代表人,注册资本,成立日期
在这里插入图片描述

2. 对目标网站,进行分析

  • 动态内容分析:

    JS和Ajax请求:确定页面是否使用JavaScript动态加载内容,如果是,需要分析Ajax请求以获取数据的API。
    在这里插入图片描述进行页面切换,抓去Ajax,发现page里面的response携带这我们所需要的数据

    找到动态变化值,一般在headers,或者payload中,动态变化值,可能就是影响批量爬虫的关键
    例中的payload是明文数据,headerssigntimestamp是动态变化值

3 .找到加密的入口

靠经验,运气,猜测,分析代码,观察数据,调试代码,逆向分析,等等。
使用关键字搜索,断点,调用堆栈等方法。

这里我使用关键字搜索
使用正则表达式搜索缩小搜索范围,勾选“Use Regular Expression”或.*并输入正则表达式,如\bSign\b—\b确定搜索边界
像Math.sign这种是js的数学库文件,可以直接排除,就10几个,慢慢排查,使用断点调试
在这里插入图片描述
这里就是目标,注意这里使用了js的逗号表达式,想要查看结果悬浮,或者在控制台中查看,注意你要在断点的作用域内,函数是有生命周期的
在这里插入图片描述

4. 扣js代码

复制js代码,模拟浏览器加密过程

这里我发现一个好用的小技巧,使用单步调试,从断点开始出发查看经过的函数基本都是我们所需的js代码,途中会跳转到其他的js文件(webpack)然后回来就可一看见MD5加密的算法了
在这里插入图片描述

5. 写代码

  1. 请求模拟
  2. 获取js逆向值
  3. py调用js
  4. 数据清洗
  5. 数据存储
  6. 处理反爬机制(ip封禁)

注意事项

  1. 下载packages的时候过慢,pip和node我都会给出镜像源
  2. 我使用的是Linux:pip install PyExecJS2,Windows:pip install PyExecJS,不行就两个都试一遍
  3. google在浏览器开发者工具中不让粘贴,可在控制台输入allow pasting
  4. 本来打算以csv文件保存,但是爬取页数一多,就打不开csv文件,所以就保存为txt
  5. 最好不要使用异步模块,这个爬取的速度不会太慢,爬取的太快服务区可能不会响应
  6. 不要大量爬去,该网站会封IP(使用代理池就可以了)

packages

  • pip
# 模拟浏览器发送请求
pip install requests -i https://mirrors.aliyun.com/pypi/simple/

# 在py中调用js
pip install PyExecJS2 -i https://mirrors.aliyun.com/pypi/simple/

# 方便实时预览进度
pip install requests -i https://mirrors.aliyun.com/pypi/simple/
  • npm
# 使用淘宝源
npm config set registry https://registry.npm.taobao.org

# 我遇到了证书过期(可能是我设置的是外国时区,使用的是国内的源),设置 npm 忽略 SSL 证书错误
npm config set strict-ssl false

npm install crypto-js

python code

import requests
import time
import execjs
import json
from tqdm import tqdm

def fetch_data(page, timer):
    json_data = {
        'eid': '',
        'achievementQueryType': 'and',
        'achievementQueryDto': [],
        'personnelQueryDto': {
            'queryType': 'and',
        },
        'aptitudeQueryDto': {
            'queryType': 'and',
            'nameStr': '',
            'aptitudeQueryType': 'and',
            'businessScopeQueryType': 'or',
            'filePlaceType': '1',
            'aptitudeDtoList': [
                {
                    'codeStr': '',
                    'queryType': 'and',
                    'aptitudeType': 'qualification',
                },
            ],
            'aptitudeSource': 'new',
        },
        'page': {
            'page': page,
            'limit': 20,
            'field': '',
            'order': '',
        },
    }

    get_sign = execjs.compile(open('jiansheku.js').read()).call('get_sign', json_data, timer)

    cookies = {
        'Hm_lvt_03b8714a30a2e110b8a13db120eb6774': '1718020163',
        'Hm_lpvt_03b8714a30a2e110b8a13db120eb6774': '1718020163',
        'HWWAFSESTIME': '1718020163509',
        'HWWAFSESID': '228fb8efd82b43680e',
    }

    headers = {
        'accept': 'application/json, text/plain, */*',
        'accept-language': 'en-US,en;q=0.9',
        'content-type': 'application/json;charset=UTF-8',
        'devicetype': 'PC',
        'origin': 'https://www.jiansheku.com',
        'page': 'search-enterprise',
        'priority': 'u=1, i',
        'referer': 'https://www.jiansheku.com/',
        'sec-ch-ua': '"Google Chrome";v="125", "Chromium";v="125", "Not.A/Brand";v="24"',
        'sec-ch-ua-mobile': '?0',
        'sec-ch-ua-platform': '"Linux"',
        'sec-fetch-dest': 'empty',
        'sec-fetch-mode': 'cors',
        'sec-fetch-site': 'same-site',
        'sign': get_sign,
        'timestamp': str(timer),
        'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36',
    }

    try:
        response = requests.post('https://capi.jiansheku.com/nationzj/enterprice/page', cookies=cookies, headers=headers, json=json_data)
        response.raise_for_status()  # 检查请求是否成功
        print(f"Page {page} fetched successfully")
        print(response.text)  # 打印响应内容以检查数据格式
        return response.json()
    except requests.RequestException as e:
        print(f"Request failed for page {page}: {e}")
        return None

def save_to_txt(all_records, filename='enterprise_data.txt'):
    with open(filename, 'w', encoding='utf-8') as file:
        headers = ['Name', 'Legal Person', 'Registered Capital', 'LiceValidity Date']
        file.write('\t'.join(headers) + '\n')
        for record in all_records:
            line = f"{record['name']}\t{record['legalPerson']}\t{record['registeredCapital']}\t{record['liceValidityDate']}\n"
            file.write(line)
    print(f"数据已保存到 {filename} 文件中")

def main():
    timer = time.time() * 1000
    max_pages = 5  # 设置要遍历的最大页数
    all_records = []

    for page in tqdm(range(1, max_pages + 1)):
        data = fetch_data(page, timer)
        if data and 'data' in data and 'list' in data['data']:
            records = [{
                'name': item['name'],
                'legalPerson': item.get('legalPerson', ''),
                'registeredCapital': item.get('registeredCapital', ''),
                'liceValidityDate': item.get('liceValidityDate', '')
            } for item in data['data']['list']]
            all_records.extend(records)
        else:
            print(f"No data found for page {page}")

    if all_records:
        # 将记录保存到txt文件
        save_to_txt(all_records)
    else:
        print("No records to save.")

if __name__ == "__main__":
    main()

js code

const Cryptojs = require("crypto-js")

ku = function(e, t, time) {
    var n = t + e + time;
    // 这里的MD5是加密算法,加密后的字符串就是签名
    return n = Cryptojs.MD5(n).toString()    // 经过单点调试,发现这里是加密算法构成的位置
}

Lu = function e(t) {
    var n;
    if (Array.isArray(t)) {
        for (var r in n = new Array,
        t) {
            var o = t[r];
            for (var i in o)
                null == o[i] ? delete t[r][i] : Array.isArray(t[r][i]) && e(t[r][i])
        }
        return n = t,
        JSON.stringify(n).replace(/^(\s|")+|(\s|")+$/g, "")
    }
    return n = t && t.constructor === Object ? JSON.stringify(t) : t
}

Tu = function(e) {
    var t = new Array
      , n = 0;
    for (var i in e)
        t[n] = i,
        n++;
    return t.sort()
}

Ou = function(e) {
    var t = Tu(e)
      , n = "";
    for (var i in t) {
        var r = Lu(e[t[i]]);
        null != r && "" != r.toString() && (n += t[i] + "=" + r + "&")
    }
    return n
}

function get_sign(param, time) {
//     param = {
//     'eid': '',
//     'achievementQueryType': 'and',
//     'achievementQueryDto': [],
//     'personnelQueryDto': {
//         'queryType': 'and',
//     },
//     'aptitudeQueryDto': {
//         'queryType': 'and',
//         'nameStr': '',
//         'aptitudeQueryType': 'and',
//         'businessScopeQueryType': 'or',
//         'filePlaceType': '1',
//         'aptitudeDtoList': [
//             {
//                 'codeStr': '',
//                 'queryType': 'and',
//                 'aptitudeType': 'qualification',
//             },
//         ],
//         'aptitudeSource': 'new',
//     },
//     'page': {
//         'page': 3,
//         'limit': 20,
//         'field': '',
//         'order': '',
//     },
// };
//     time = (new Date).getTime();
    t = Ou(param);

return ku("ghaepVf6IhcHmgnk4NCTXLApxQkBcvh1", ku("mwMlWOdyM7OXbjzQPulT1ndRZIAjShDB", ku("ZuSj0gwgsKXP4fTEz55oAG2q2p1SVGKK", t, time), time), time);
}

// console.log(get_sign());

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1829619.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

win10没有Hyper-v的解决方法

win10没有Hyper-v的解决方法 问题:最近想装下docker,但是在控制面板-程序-启用或关闭Windows功能下找不到Hyper-v节点。 废话不多说,直接上实操教程 1.将下面命令复制到文本文档中,并将文档重命名Hyper.cmd pushd "%~dp0&q…

29.添加录入注入信息界面

上一个内容:28.启动与暂停程序 以 28.启动与暂停程序 它的代码为基础进行修改 效果图: 新建Dialog 给新建的dialog添加空间,如下图 给每个输入框创建一个变量 代码: void CWndAddGame::OnBnClickedButton1() {static TCHAR BASE…

Go如何在本地引用以及发布并引用自定义工具包

如何引用本地自定义工具包 我们首先要准备两个项目,分别为需要引入的工具包和当前项目。 myutils、myproject1. myutils为我们的项目1-工具包 package mypakgeimport "strings"func IsContains(s string) bool {if strings.Contains(s, "a")…

HAL库开发--定时器的配置方式和占空比输出

知不足而奋进 望远山而前行 目录 文章目录 前言 目标 内容 需求 Timer配置 分频系数 Timer编码 总结 前言 定时器(Timer)在嵌入式系统中是一种重要的硬件资源,常用于生成精确的时间延迟、周期性触发事件或产生PWM信号等应用。本文将…

排序算法!

文章目录 插入排序冒泡排序选择排序归并排序希尔排序 提示:本文分析算法复杂度时,默认目标是n个元素升序排序,代码注释已经写好,就不单独拎出来了 插入排序 插入排序就是把待排序序列的第一个元素看作是有序序列,把第…

Internet Download Manager(IDM6.41)软件安装包下载及安装教程

Internet Download Manager有一个智能下载逻辑加速器,具有智能动态文件分割和安全的多部分下载技术,可以加速下载。与其他下载加速器和管理器不同,Internet下载管理器在下载开始之前对文件进行分段,而Internet下载管理器在下载过程…

华为云下Ubuntu20.04中Docker的部署

我想用Docker拉取splash,Docker目前已经无法使用(镜像都在国外)。这导致了 docker pull 命令的失败,原因是timeout。所以我们有必要将docker的源设置在国内,直接用国内的镜像。 1.在华为云下的Ubuntu20.04因为源的原因…

AMD Lisa Su专访:谈与英伟达、Intel竞争 直言Arm不是敌人

AMD CEO Lisa Su(苏姿丰)绝对称得上是芯片届的风云人物,尤其是进入了AI新时代,她的声望达到了十年来最高点。翻看其成长历史,苏姿丰在麻省理工学院获得电气工程博士学位后(在麻省理工学院学习八年半&#x…

【Ardiuno】实验使用OPT语音模块播放语音(图文)

当我们需要在程序中播放语音内容时,就需要使用到语音模块,今天我们就来实验一下使用OPT语音模块来方法语音。 const int voicePin 5; const int voiceBusyPin 18; const int testLEDPin 2;unsigned long pmillis 0;int busyVal 0; …

C#联合Halcon机器视觉框架源码—升级版

相较于之前的NxtVision,本软件代码架构更加合理,且新增ui设计器、原来的vb脚本改为C#脚本,并尝试将视觉与运动控制相结合,是一体化的框架。 对源码有需求的,订阅本专栏后,私信我领取。

安卓网络通信(多线程、HTTP访问、图片加载、即时通信)

本章介绍App开发常用的以下网络通信技术,主要包括:如何以官方推荐的方式使用多线程技术,如何通过okhttp实现常见的HTTP接口访问操作,如何使用Dlide框架加载网络图片,如何分别运用SocketIO和WebSocket实现及时通信功能等…

记录一次centos扩容

背景 在Vscode上连虚拟机写项目,突然提示磁盘空间不足(no space left on device),一开始打算删些东西,这里参考博客,写得挺清楚的,但是操作后我发现实在没啥文件可以删除,所以干脆不删了,直接扩…

Centos实现Mysql8.4安装及主主同步

8.4的Msyql在同步的时候与之前的版本有很大不同,这里记录一下安装流程 Mysql安装 官网下载 选择自己的版本,选第一个 复制下载链接 在服务器上创建一个msyql目录 使用命令下载,链接换自己的 wget https://dev.mysql.com/get/mysql84-community-relea…

【分布式计算】java消息队列机制

消息队列是一种在不同组件或应用之间进行数据传递的技术,通常用于处理异步通信。它允许消息的发送者(生产者)和接收者(消费者)之间进行解耦。 概念 消息队列是一种先进先出(FIFO)的数据结构&…

【react小项目】bmi-calculator

bmi-calculator 目录 bmi-calculator初始化项目01大致布局01代码 02完善样式02代码 03输入信息模块03代码 04 使用图表04代码 05详细记录信息渲染05代码 06 让数据变成响应式的06-1输入框的数据处理06-2图表,和记录信息的区域数据处理 07 删除功能,撤销功…

DeepDriving | 经典的目标检测算法:CenterNet

本文来源公众号“DeepDriving”,仅用于学术分享,侵权删,干货满满。 原文链接:经典的目标检测算法:CenterNet 1 前言 CenterNet是2019年发表的一篇文章《Objects as Points》中提出的一个经典的目标检测算法&#xf…

仓储管理系统WMS构架设计B/S和C/S:如何选?

导语 大家好,我是社长,老K。专注分享智能制造和智能仓储物流等内容。 新书《智能物流系统构成与技术实践》 在设计仓库管理系统(WMS)时,架构的选择至关重要,因为它直接影响到系统的可用性、可维护性、灵活性…

17岁中专女生,闯进全球数学竞赛12强

今年阿里的数学竞赛结果出来了,在榜单的前列包含一个 17 岁的中专女生。 在 2018 年时,阿里巴巴达摩院发起了一个国际数学竞赛,基本每年举办一次,参赛不设报名条件,向全球所有数学爱好者开放,竞赛由阿里创…

从FasterTransformer源码解读开始了解大模型(2.1)代码通读02

从FasterTransformer源码解读开始了解大模型(2.0)代码解读02-初始化和forward 写在前面的话 本篇的内容主要是介绍ParallelGpt.cc中的代码内容,首先介绍一些初始化和工具函数,然后会从forward主函数开始介绍一部分。 零、初始化…

【ROS里程计】中部分代码解释

bool OdomNodePub::Odom_Reset(ubt_odom::odomreset::Request& req, ubt_odom::odomreset::Response& res) {if(req.cmd "reset"){OdomResetFlag true;}else{OdomResetFlag false;}res.state "success";return true; } 该函数是一个ROS节点中…