Python 模拟执行 JavaScript 教程
目录
为什么需要这技能?
如今 Web 开发的核心逻辑早已不再是单纯的后端渲染 HTML。前端渲染、接口参数加密、动态 Cookie 生成,这些活儿几乎全由 JavaScript 扛起。作为开发者或爬虫工程师,你大概率会碰到下面这些场景:
- 抓取 B 站番剧或评论,得先搞定
bili_jct、_signature这类加密参数。 - 爬电商平台的商品库存,需要拿到动态生成的
anti_scrape_token。 - 补全前后端分离项目的自动化测试,Python 构造的数据必须经过前端加密才能通过后端校验。
面对这些情况,能在 Python 里直接跑 JavaScript 逻辑,就能省下大量逆向和重写的时间。本教程将用 PyExecJS 这个轻量库,教你如何把前端 JS 代码无缝搬进 Python,全程不牵扯高深数学,只讲实用的执行技巧。
环境快速搭建
核心依赖
想要 Python 模拟执行 JavaScript,你需要两样东西:
- PyExecJS:Python 和 JS 运行环境之间的桥梁。
- JS 运行环境:强烈推荐 Node.js。它的 V8 引擎原生支持 ES6+ 以及
crypto-js这类第三方加密库,比 Windows 自带的 JScript 好用太多。
一步一步安装
1. 安装 PyExecJS
2. 安装 Node.js
去官网下载最新的 LTS 版本(稳定省心):
安装完成后,打开终端验证:
3. 强制绑定 Node.js(关键!)
很多新手装完 PyExecJS 后,系统默认会使用 Windows 自带的 JScript(不支持 ES6+),导致代码一跑就报错。所以一定要主动检查并绑定 Node.js:
看到 Node.js (V8) 就说明环境已经稳妥了。
实战:破解某球星站加密 Token
我们拿官方提供的 SPA7 爬虫练习站(https://spa7.scrape.center/)练手。这个站点里每个球星信息都由一个加密的 token 保护,只有正确生成该 token,才能请求到完整的球员数据。
第一步:前端加密逻辑逆向
先别急着写 Python 代码,打开浏览器的开发者工具(F12),跟着下面步骤走,锁定加密逻辑:
- 切换到 Network(网络)标签。
- 刷新页面,找出返回完整球员信息的请求(通常包含
api或detail)。 - 查看请求参数,你会看到有一个很显眼的加密字段:
token。 - 点击 Initiator(启动器)标签,找到发起该请求的 JS 文件位置。
- 进去后用
Ctrl+F搜索getToken(加密函数的常见命名),定位具体加密代码。
第二步:提取并准备加密代码
在练习站中,getToken 函数依赖了 crypto-js 这个第三方库来执行 DES 加密。为了让它在 Node.js 里正常运行,我们需要做两件事:
- 获取
crypto-js的压缩版crypto-js.min.js(可以直接从 npm 或 CDN 下载)。 - 把加密函数和
crypto-js.min.js合并到同一个 JS 文件里,并手动解决全局变量挂载问题。
第三步:Python 无缝调用
先整理加密文件(crypto_utils.js)
Node.js 默认不会把第三方库暴露成全局对象,因此我们需要用一个自执行函数手动返回 CryptoJS,并挂到全局:
再写 Python 调用代码
运行这段代码,你应该能看到一串 Base64 格式的加密 token,和浏览器请求里的一模一样。
避坑指南+性能小技巧
1. 避坑:CryptoJS 未定义
原因:Node.js 环境下直接 require('crypto-js') 不会自动挂到全局,我们的自执行函数如果没正确返回,也会导致 CryptoJS is not defined 报错。
解决方案:
- 严格使用上文的自执行函数 + 全局挂载方式。
- 或者在 Python 里预先安装并引入:
ctx.eval("const CryptoJS = require('crypto-js')")
前提是当前目录下已经执行npm install crypto-js。
2. 避坑:中文字符乱码
表现:如果加密对象中含有中文,生成出来的 token 和浏览器里的不一致,请求会被拒绝。
解决方案:
- 确保 JS 文件保存为 UTF-8 without BOM 编码(避免 Windows 记事本的默认编码)。
- Python 读取 JS 文件时务必指定
encoding='utf-8'。
3. 性能优化:别每次都编译 JS!
PyExecJS 的 编译过程最耗时,因为每编译一次都会新开一个 Node.js 子进程。如果你要爬 1000 个球星数据,却在循环里反复 execjs.compile,性能会直接崩掉。
优化方式:把 execjs.compile() 提到循环外面,整个脚本只执行一次,一直复用同一个 ctx 对象。
这条小技巧在批量调用 JS 函数时能带来质的提升。
总结
通过这篇教程,你掌握了以下核心能力:
- 如何正确安装并绑定 PyExecJS + Node.js 的运行环境。
- 从浏览器开发者工具逆向出前端加密逻辑的基本思路。
- 将依赖第三方库的 JS 加密代码无缝迁移到 Python 中执行。
- 解决
CryptoJS未定义、中文乱码等常见坑,以及通过预编译提升执行性能。
如果未来遇到更复杂的加密——比如高度混淆的 JS 或 WebAssembly,你也可以选择两条路:
- 进一步研究 JS 逆向(例如 AST 还原、脚本行为分析)。
- 使用 Selenium / Playwright 这类浏览器自动化工具,牺牲一些性能,但跳过了手动逆向的步骤。
完整示例代码可访问对应的 GitHub 仓库:
https://github.com/Python3WebSpider/ScrapeSpa7

