知识

python调用js脚本

时间:2010-12-5 17:23:32  作者:知识   来源:知识  查看:  评论:0
内容摘要: python调用js脚本 我干过一件蠢事:用python爬一个加密接口,对方前端代码里有个AES解密函数,我硬是用python重写了整个加密逻辑。折腾两小时,最后发现少了个padding参数,数据全

python调用js脚本

我干过一件蠢事:用python爬一个加密接口,调用对方前端代码里有个AES解密函数,脚本我硬是调用用python重写了整个加密逻辑。折腾两小时,脚本最后发现少了个padding参数,调用数据全乱码。脚本后来学乖了——直接拿python调那段js,调用十行代码解决战斗。脚本

这事儿的调用本质是:python和js各有各的生态,很多加密、脚本签名逻辑已经写死在js里,调用你没必要用python再造轮子。脚本尤其是调用那些依赖浏览器环境的库(比如某些webpack打包后的模块),纯python模拟起来痛苦得要命。脚本

最粗暴的调用方式:subprocess + node

如果你机器上装了node,那最简单。把js脚本存成文件,用subprocess调node执行,传参靠stdin或命令行参数,输出靠stdout。

import subprocess, json result = subprocess.run( ['node', 'encrypt.js', 'hello'], capture_output=True, text=True, encoding='utf-8' ) print(result.stdout) # 拿到js打印的结果

这招适合一次性调用,但每次启动node进程开销不小。你要是循环调几百次,光进程启动时间就够你喝一壶的。我试过在循环里调node,1000次请求硬是跑了40秒,后来换方案才压到3秒。

正经办法:pyexecjs

pyexecjs是个老牌库,它帮你管理一个js运行时,不用频繁启进程。用法很直白:

import execjs ctx = execjs.compile(""" function add(a, b) {  return a + b; } """) print(ctx.call("add", 3, 4)) # 7

默认它用的是系统里的js引擎(Windows上可能是JScript,Linux上没装node的话会报错)。所以你得先装node,然后execjs会自动优先用node。这货有个坑——它内部用eval执行js字符串,如果你的js代码里有中文注释或者特殊字符,可能编码会出问题。我的经验是:把js代码里所有中文注释删干净再喂给它,否则报错你根本看不懂。

进阶:py_mini_racer,快得离谱

后来我发现了py_mini_racer,这玩意儿直接内嵌了V8引擎,不用调外部进程,速度比pyexecjs快一个量级。安装也简单:

pip install py_mini_racer

用起来几乎一样:

from py_mini_racer import MiniRacer ctx = MiniRacer() ctx.eval(""" function decrypt(data) {  return CryptoJS.AES.decrypt(data, 'secret').toString(CryptoJS.enc.Utf8); } """) # 但注意,它默认没有CryptoJS,你得自己把整个库的源码拼进去

这里有个关键点:py_mini_racer不提供浏览器环境,没有window、document、localStorage这些。你调用的js必须纯逻辑,不能依赖DOM。我遇到过最恶心的场景——某个加密库内部偷偷用了`window.btoa`,结果在V8里直接报undefined。解决办法是手动在js代码顶部垫一层polyfill:

globalThis.window = globalThis; globalThis.btoa = (str) => Buffer.from(str, 'binary').toString('base64'); // 然后才是你的业务js

这种补丁打多了你会觉得自己在给V8做移植手术,但确实管用。

最后聊个容易翻车的细节:异步js

很多js加密函数是异步的,比如用`async/await`或者返回Promise。python这边是同步的,直接调用会拿不到结果。py_mini_racer有个`call`方法支持传一个回调函数,但用起来别扭。我的土办法是——把异步函数包一层同步逻辑,用`deasync`或者`child_process`强行同步化。比如js里原本是`await getToken()`,你就改成用`child_process.spawnSync`去跑一个独立的node脚本,把异步结果通过文件或stdout传回来。丑是丑了点,但稳。

说到底,python调js不是什么高深技术,核心就一句话:找到你的js运行环境,把数据塞进去,把结果接出来。别想着在python里模拟一切,该用node就用node,该垫polyfill就垫。我现在的习惯是——凡是遇到复杂加密,先花10分钟试试py_mini_racer能不能直接跑,跑不通就退回subprocess方式,再不行就考虑用selenium直接驱动浏览器。反正能跑就行,别纠结优雅。

哦对了,最后提醒一句:调js之前先确认你确实有权限用那段js代码,别为了爬数据把自己搞进法律纠纷里。技术无罪,但用技术的人得长点心。

最近更新
热门排行
copyright © 2026 powered by 力不从心网   sitemap