在 Node.js 中调用打包后的 Python 可执行文件(如 PyInstaller 生成的 .exe
或二进制文件),可以通过以下步骤实现:
一、Python 打包准备
假设已有打包好的 Python 文件 your_script.exe
(以 Windows 为例),核心功能如下:
# your_script.py
import sys, jsonif __name__ == "__main__":# 接收来自命令行的输入参数input_data = json.loads(sys.argv[1])result = {"output": input_data["num"] * 2}# 输出结果到标准输出print(json.dumps(result))
使用 PyInstaller 打包:
pyinstaller --onefile your_script.py # 生成 dist/your_script.exe
二、Node.js 调用方案
通过 child_process
模块执行外部程序,推荐以下两种方式:
方案 1:使用 spawn
处理流式数据
const { spawn } = require('child_process');
const path = require('path');// 定义打包文件路径(跨平台兼容)
const pythonExe = path.join(__dirname, 'dist', 'your_script.exe');function runPythonScript(inputData) {return new Promise((resolve, reject) => {// 启动子进程const pythonProcess = spawn(pythonExe, [JSON.stringify(inputData)]);let result = '';let errorOutput = '';// 捕获标准输出pythonProcess.stdout.on('data', (data) => {result += data.toString();});// 捕获错误输出pythonProcess.stderr.on('data', (data) => {errorOutput += data.toString();});// 处理进程结束pythonProcess.on('close', (code) => {if (code !== 0) {reject(new Error(`Process exited with code ${code}: ${errorOutput}`));} else {try {resolve(JSON.parse(result));} catch (e) {reject(new Error('Failed to parse JSON output'));}}});});
}// 调用示例
(async () => {try {const response = await runPythonScript({ num: 42 });console.log('Result:', response.output); // 输出: 84} catch (error) {console.error('Error:', error.message);}
})();
方案 2:使用 execFile
执行简单命令
const { execFile } = require('child_process');
const path = require('path');const pythonExe = path.join(__dirname, 'dist', 'your_script.exe');function runPythonScript(inputData) {return new Promise((resolve, reject) => {execFile(pythonExe,[JSON.stringify(inputData)],(error, stdout, stderr) => {if (error) {reject(error);return;}if (stderr) {reject(new Error(stderr));return;}try {resolve(JSON.parse(stdout));} catch (e) {reject(new Error('Invalid JSON output'));}});});
}
三、关键注意事项
-
路径处理
- 使用
path.join()
确保跨平台路径兼容性 - 部署时确认打包文件的绝对路径
- 使用
-
参数传递
- 通过命令行参数 (
process.argv
) 或 STDIN 传递数据 - 复杂数据建议使用 JSON 序列化
- 通过命令行参数 (
-
错误处理
- 检查进程退出码 (
code !== 0
) - 捕获
stderr
输出和 JSON 解析异常
- 检查进程退出码 (
-
性能优化
- 频繁调用时复用子进程(需实现进程池)
- 避免阻塞 Event Loop,使用异步操作
-
安全防护
- 对输入参数做合法性校验
- 避免直接将用户输入拼接为命令行参数(防命令注入)
四、跨平台兼容技巧
-
文件扩展名处理
const pythonExe = process.platform === 'win32' ? path.join(__dirname, 'dist', 'your_script.exe'): path.join(__dirname, 'dist', 'your_script');
-
执行权限设置
Linux/macOS 需添加可执行权限:chmod +x dist/your_script
-
环境变量传递
通过env
参数传递特定环境变量:spawn(pythonExe, [args], {env: { ...process.env, CUSTOM_VAR: 'value' } });
五、完整工作流示例
-
Python 端
实现业务逻辑并打包:pip install pyinstaller pyinstaller --onefile your_script.py
-
Node.js 端
部署打包文件并调用:your-project/ ├── node_modules/ ├── dist/ │ └── your_script.exe # 或 Linux/macOS 可执行文件 └── index.js # Node.js 主程序
-
测试执行
node index.js
通过这种方式,您可以在 Node.js 应用中无缝集成 Python 功能模块,同时保持环境隔离和部署便捷性。