JS逆向爬虫教程与实战技巧

想要一个关于爬虫JS逆向的详细教程。这是一个很专业的技术需求,最近有个可能是正在学习爬虫技术的开发者或者数据分析师,遇到了需要破解JavaScript加密的反爬机制的问题,想让我出一期实战教程,话不多说,开干。

以下是我整理的一份系统化的爬虫JS逆向教程,结合实战技巧与工具使用,能有效的突破前端加密参数限制。内容涵盖基础原理、调试方法、扣代码技巧及高效解决方案:

一、JS逆向核心流程

寻找加密入口 

Network分析:捕获目标请求(XHR/fetch),定位加密参数(如token、sign、xyz) 

全局搜索:在Sources面板按Ctrl+Shift+F搜索参数名(如"nonce"、password:) 

调用栈追踪:通过Network请求的Initiator标签回溯加密逻辑触发点 

调试分析技巧 

代码格式化:点击Sources面板左下角 {} 美化压缩代码 

断点类型: 

XHR断点:针对特定URL拦截请求 

事件断点:监听click、submit等DOM事件 

条件断点:在加密函数内设置Conditional Breakpoint 

Scope面板:查看局部变量、闭包域中的关键值(如密钥、盐值) 

模拟执行方案 

方法适用场景工具示例

扣JS代码逻辑简单、无环境依赖execjs(Python调用)

RPC通信复杂混淆/浏览器环境依赖Sekiro

无头浏览器需完整渲染流程PlayWright/Selenium

二、实战案例解析(以汽车之家登录为例)

目标定位 

登录请求中pwd参数为MD5加密: 

# 原始请求示例

FormData: {username:"test",pwd:"d6d7d5a8c4e6e7b8"}

逆向步骤: 

步骤1:在Sources搜索pwd,定位到login.js文件 

步骤2:发现关键函数 hex_md5(s),其结构如下: 

functionhex_md5(s) {

returnbinl2hex(core_md5(str2binl(s),s.length*chrsz));

}//

步骤3:扣取完整MD5相关函数(core_md5, binl2hex, str2binl) 

步骤4:Python通过execjs调用: 

importexecjs

withopen('qichezhijia.js','r',encoding='utf-8')asf:

js_code=f.read()

ctx=execjs.compile(js_code)

encrypted_pwd=ctx.call('hex_md5','123456')# 输出:d6d7d5a8c4e6e7b8

三、高级技巧

Hook拦截 

使用Tampermonkey注入脚本监听关键函数(如btoa、encrypt): 

// Hook Base64示例

(function() {

varoriginBtoa=window.btoa;

window.btoa=function(data) {

console.log("Base64 input:",data);

returnoriginBtoa(data);

  }

})();

反混淆方案 

控制流平坦化:使用AST还原工具(如babel) 

字符串阵列化:动态执行提取真实字符串 

Overrides覆盖 

Chrome的Local Overrides功能替换线上JS文件 

注入调试代码或修复环境检测(如补全window对象) 

四、常见加密类型与对策

哈希算法(MD5/SHA1):扣取标准算法实现(如本文MD5案例) 

RSA加密:提取公钥 + 使用rsa库(苏宁易购登录案例) 

动态参数: 

时间戳:同步生成 

随机数:Math.random()重放或固定盐值 

自定义编码:Base64变异/移位编码 → Hook charCodeAt分析 

五、注意事项

合法合规:遵守robots.txt,避免高频请求 

更新维护:网站JS变动时需重新分析 

性能权衡: 

简单加密 → 扣代码(高效) 

复杂方案 → RPC/无头浏览器(稳定) 

通过上面教程,我们可掌握从基础断点调试到复杂RPC调用的全链路JS逆向技能。遇到具体网站难题时,建议结合Chrome DevTools动态分析快速定位突破点。

具体实战代码示例我公布在下面。

以下是一个完整的JS逆向爬虫实战代码示例,以汽车之家登录密码加密为例,演示如何逆向分析并实现自动化登录:

1. 目标分析(浏览器开发者工具操作)

在汽车之家登录页面:

打开Chrome开发者工具(F12)

输入用户名/密码点击登录

在Network面板查看登录请求,发现密码字段为加密值:

{

"username":"test@example.com",

"pwd":"d6d7d5a8c4e6e7b8",// 123456的加密结果

"remember":1

}

2. JS逆向代码实现

步骤1:提取加密JS代码

在Sources面板找到login.js,定位并提取MD5加密函数:

// 保存为 autohome_md5.js

functionhex_md5(s) {

returnbinl2hex(core_md5(str2binl(s),s.length*chrsz));

}

functioncore_md5(x,len) {

/* 此处省略完整MD5算法实现,实际需扣取完整200行代码 */

}

functionstr2binl(str) {

varbin=Array();

varmask=(1<<chrsz)-1;

for(vari=0;i<str.length*chrsz;i+=chrsz)

bin[i>>5]|=(str.charCodeAt(i/chrsz)&mask)<<(i%32);

returnbin;

}

functionbinl2hex(binarray) {

varhex_tab="0123456789abcdef";

varstr="";

for(vari=0;i<binarray.length*4;i++) {

str+=hex_tab.charAt((binarray[i>>2]>>((i%4)*8+4))&0xF)+

hex_tab.charAt((binarray[i>>2]>>((i%4)*8))&0xF);

  }

returnstr;

}

varchrsz=8;// 字符位数 (8-bit)

步骤2:Python爬虫实现

importexecjs

importrequests

fromurllib.parseimporturlencode

classAutoHomeSpider:

def__init__(self):

# 加载JS加密代码

withopen('autohome_md5.js','r',encoding='utf-8')asf:

self.js_code=f.read()

self.ctx=execjs.compile(self.js_code)


self.session=requests.Session()

self.headers={

'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36',

'Origin':'https://account.autohome.com.cn'

       }

defencrypt_password(self,password):

"""JS逆向加密密码"""

returnself.ctx.call('hex_md5',password)

deflogin(self,username,password):

"""执行登录操作"""

login_url='https://account.autohome.com.cn/api/login'


# 加密密码

encrypted_pwd=self.encrypt_password(password)


# 构造表单数据

form_data={

'username':username,

'pwd':encrypted_pwd,

'remember':1,

'vcode':'',

'redirect':'https://www.autohome.com.cn/'

       }


# 发送登录请求

response=self.session.post(

url=login_url,

data=form_data,

headers=self.headers

       )


# 检查登录结果

result=response.json()

ifresult['returncode']==0:

print(f"登录成功! 用户名: {username}")

print(f"Cookies: {self.session.cookies.get_dict()}")

returnTrue

else:

print(f"登录失败: {result['message']}")

returnFalse

defget_user_info(self):

"""获取用户信息(需登录后)"""

info_url='https://account.autohome.com.cn/api/GetUserInfo'

response=self.session.get(info_url,headers=self.headers)

returnresponse.json()

if__name__=="__main__":

spider=AutoHomeSpider()


# 测试账号(请替换为实际账号)

USERNAME="your_username@example.com"

PASSWORD="your_password"


ifspider.login(USERNAME,PASSWORD):

user_info=spider.get_user_info()

print("用户信息:",user_info)

3. 复杂场景解决方案(RPC通信)

当遇到环境检测或复杂混淆时,使用Sekiro实现JS桥接:

# Python端 (Sekiro客户端)

fromsekiroimportSekiroClient

sekiro=SekiroClient("your-group-name","your-client-id")

@sekiro.action("encrypt")

defhandle_encrypt(params):

password=params["password"]

# 调用浏览器环境执行加密

return{"encrypted":sekiro.invoke_browser("encryptPassword",password)}

// 浏览器端 (Tampermonkey脚本)

SekiroClient.register("encryptPassword", function(password) {

// 在真实浏览器环境中执行加密

return window.encryptFunction(password);

});

4. 常见错误处理

# 在加密函数中添加错误处理

def encrypt_password(self, password):

try:

return self.ctx.call('hex_md5', password)

except execjs.RuntimeError as e:

# 处理JS执行错误

print(f"JS执行错误: {e}")

# 降级方案:使用Python的MD5实现

import hashlib

return hashlib.md5(password.encode()).hexdigest()

except Exception as e:

print(f"加密失败: {e}")

return None

5. 完整项目结构

js_reverse_demo/

├── autohome_md5.js    # 扣取的加密JS

├── autohome_spider.py # 主爬虫程序

├── requirements.txt  # 依赖文件

└── sekrio_client.py  # RPC桥接文件

requirements.txt内容

requests==2.31.0

PyExecJS==1.5.1

nodejs==0.1.1  # 需要安装Node.js环境

关键点说明:

完整扣取JS:必须确保核心加密函数及其所有依赖函数都被完整提取

环境一致性:注意JS中的全局变量(如chrsz)需在扣取代码中保留

错误降级:准备备用加密方案应对JS执行失败

请求仿真:需复制所有必要的请求头(特别是Content-Type和Origin)

会话保持:使用requests.Session维持cookies

这里需要注意的是,实际项目中,我们需根据目标网站的加密实现调整扣取的JS代码。可通过Chrome Overrides功能持久化调试修改后的JS文件(Sources > Overrides > Enable Local Overrides)。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容