在 Node.js 中调用打包后的 Python 可执行文件(如 PyInstaller 生成的 .exe
或二进制文件),可以通过以下步骤实现:
一、Python 打包准备
假设已有打包好的 Python 文件 your_script.exe
(以 Windows 为例),核心功能如下:
python
# your_script.py
import sys, json
if __name__ == "__main__":
# 接收来自命令行的输入参数
input_data = json.loads(sys.argv[1])
result = {"output": input_data["num"] * 2}
# 输出结果到标准输出
print(json.dumps(result))
使用 PyInstaller 打包:
bash
pyinstaller --onefile your_script.py # 生成 dist/your_script.exe
二、Node.js 调用方案
通过 child_process
模块执行外部程序,推荐以下两种方式:
方案 1:使用 spawn
处理流式数据
javascript
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
执行简单命令
javascript
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,使用异步操作
-
安全防护
- 对输入参数做合法性校验
- 避免直接将用户输入拼接为命令行参数(防命令注入)
四、跨平台兼容技巧
-
文件扩展名处理
javascriptconst pythonExe = process.platform === 'win32' ? path.join(__dirname, 'dist', 'your_script.exe') : path.join(__dirname, 'dist', 'your_script');
-
执行权限设置
Linux/macOS 需添加可执行权限:
bashchmod +x dist/your_script
-
环境变量传递
通过
env
参数传递特定环境变量:javascriptspawn(pythonExe, [args], { env: { ...process.env, CUSTOM_VAR: 'value' } });
五、完整工作流示例
-
Python 端
实现业务逻辑并打包:
bashpip install pyinstaller pyinstaller --onefile your_script.py
-
Node.js 端
部署打包文件并调用:
bashyour-project/ ├── node_modules/ ├── dist/ │ └── your_script.exe # 或 Linux/macOS 可执行文件 └── index.js # Node.js 主程序
-
测试执行
bashnode index.js
通过这种方式,您可以在 Node.js 应用中无缝集成 Python 功能模块,同时保持环境隔离和部署便捷性。