我有一个Express Node.js应用程序,但我也有一个机器学习算法可以在Python中使用。有没有办法可以从我的Node.js应用程序调用Python函数来利用机器学习库的强大功能?
答案 0 :(得分:167)
我知道最简单的方法是使用随节点打包的“child_process”包。
然后你可以做类似的事情:
const spawn = require("child_process").spawn;
const pythonProcess = spawn('python',["path/to/script.py", arg1, arg2, ...]);
然后你需要做的就是确保你的python脚本中有import sys
,然后你可以使用arg1
,sys.argv[1]
使用arg2
访问sys.argv[2]
}}, 等等。
要将数据发送回节点,只需在python脚本中执行以下操作:
print(dataToSendBack)
sys.stdout.flush()
然后节点可以使用以下方式监听数据:
pythonProcess.stdout.on('data', (data) => {
// Do something with the data returned from python script
});
由于这允许使用spawn将多个参数传递给脚本,因此可以重构python脚本,以便其中一个参数决定调用哪个函数,另一个参数传递给该函数,等等。
希望这很清楚。如果有需要澄清,请告诉我。
答案 1 :(得分:61)
示例适用于来自Python背景并希望在Node.js应用程序中集成其机器学习模型的人员:
它使用child_process
核心模块:
const express = require('express')
const app = express()
app.get('/', (req, res) => {
const { spawn } = require('child_process');
const pyProg = spawn('python', ['./../pypy.py']);
pyProg.stdout.on('data', function(data) {
console.log(data.toString());
res.write(data);
res.end('end');
});
})
app.listen(4000, () => console.log('Application listening on port 4000!'))
在Python脚本中不需要sys
模块。
以下是使用Promise
执行任务的更加模块化的方式:
const express = require('express')
const app = express()
let runPy = new Promise(function(success, nosuccess) {
const { spawn } = require('child_process');
const pyprog = spawn('python', ['./../pypy.py']);
pyprog.stdout.on('data', function(data) {
success(data);
});
pyprog.stderr.on('data', (data) => {
nosuccess(data);
});
});
app.get('/', (req, res) => {
res.write('welcome\n');
runPy.then(function(fromRunpy) {
console.log(fromRunpy.toString());
res.end(fromRunpy);
});
})
app.listen(4000, () => console.log('Application listening on port 4000!'))
答案 2 :(得分:20)
python-shell
extrabacon
模块是一种从Node.js运行Python脚本的简单方法,它具有基本但有效的进程间通信和更好的错误处理。
安装: npm install python-shell
。
var PythonShell = require('python-shell');
PythonShell.run('my_script.py', function (err) {
if (err) throw err;
console.log('finished');
});
var PythonShell = require('python-shell');
var options = {
mode: 'text',
pythonPath: 'path/to/python',
pythonOptions: ['-u'],
scriptPath: 'path/to/my/scripts',
args: ['value1', 'value2', 'value3']
};
PythonShell.run('my_script.py', options, function (err, results) {
if (err)
throw err;
// Results is an array consisting of messages collected during execution
console.log('results: %j', results);
});
有关完整文档和源代码,请查看https://github.com/extrabacon/python-shell
答案 3 :(得分:12)
Node.js的子进程模块提供了以非JavaScript语言(如Python)运行脚本或命令的功能。我们可以将机器学习算法,深度学习算法和许多通过Python库提供的功能实现到Node.js应用程序中。子进程模块允许我们在Node.js应用程序中运行Python脚本,并将数据流入/流出Python脚本。
child_process.spawn():这个方法可以帮助我们异步地生成子进程。
让我们创建一个简单的Python脚本,它将两个命令行参数作为名字和姓氏,然后显示它们。稍后我们将从Node.js应用程序运行该脚本并在浏览器窗口中显示输出。
Python脚本:
import sys
# Takes first name and last name via command
# line arguments and then display them
print("Output from Python")
print("First name: " + sys.argv[1])
print("Last name: " + sys.argv[2])
# Save the script as hello.py
Node.js服务器代码:
// Import Express.js JavaScript module into the application
// and creates its variable.
var express = require('express');
var app = express();
// Creates a server which runs on port 3000 and
// can be accessed through localhost:3000
app.listen(3000, function() {
console.log('server running on port 3000');
} )
// Function callName() is executed whenever
// the URL is of the form localhost:3000/name
app.get('/name', callName);
function callName(req, res) {
// Use child_process.spawn method from
// child_process module and assign it
// to variable spawn
var spawn = require("child_process").spawn;
// Parameters passed in spawn -
// 1. type_of_script
// 2. List containing Path of the script
// and arguments for the script
// E.g.: http://localhost:3000/name?firstname=Mike&lastname=Will
// So, first name = Mike and last name = Will
var process = spawn('python',["./hello.py",
req.query.firstname,
req.query.lastname] );
// Takes stdout data from script which executed
// with arguments and send this data to res object
process.stdout.on('data', function(data) {
res.send(data.toString());
} )
}
// Save code as start.js
保存Python脚本和服务器脚本代码后,通过以下命令从其源文件夹运行代码:
node start.js
答案 4 :(得分:9)
您现在可以使用支持Python和Javascript的RPC库,例如zerorpc
在他们的首页上:
Node.js客户端
function App() {
return (
<Switch>
<Route exact path="/dashboard" component={Dashboard} />
<Route path="/" component={Wrapper} />
</Switch>
);
}
Python服务器
var zerorpc = require("zerorpc");
var client = new zerorpc.Client();
client.connect("tcp://127.0.0.1:4242");
client.invoke("hello", "RPC", function(error, res, more) {
console.log(res);
});
答案 5 :(得分:1)
我在节点10上,子进程1.0.2
。来自python的数据是一个字节数组,必须进行转换。这是在python中发出http请求的另一个快速示例。
const process = spawn("python", ["services/request.py", "https://www.google.com"])
return new Promise((resolve, reject) =>{
process.stdout.on("data", data =>{
resolve(data.toString()); // <------------ by default converts to utf-8
})
process.stderr.on("data", reject)
})
import urllib.request
import sys
def karl_morrison_is_a_pedant():
response = urllib.request.urlopen(sys.argv[1])
html = response.read()
print(html)
sys.stdout.flush()
karl_morrison_is_a_pedant()
p.s。这不是一个人为的示例,因为节点的http模块不会加载我需要发出的一些请求
答案 6 :(得分:1)
大多数先前的答案都在on(“ data”)中称呼诺言的成功,这不是正确的方法,因为如果您收到大量数据,您只会得到第一部分。相反,您必须在结束事件上执行此操作。
const { spawn } = require('child_process');
const pythonDir = (__dirname + "/../pythonCode/"); // Path of python script folder
const python = pythonDir + "pythonEnv/bin/python"; // Path of the Python interpreter
/** remove warning that you don't care about */
function cleanWarning(error) {
return error.replace(/Detector is not able to detect the language reliably.\n/g,"");
}
function callPython(scriptName, args) {
return new Promise(function(success, reject) {
const script = pythonDir + scriptName;
const pyArgs = [script, JSON.stringify(args) ]
const pyprog = spawn(python, pyArgs );
let result = "";
let resultError = "";
pyprog.stdout.on('data', function(data) {
result += data.toString();
});
pyprog.stderr.on('data', (data) => {
resultError += cleanWarning(data.toString());
});
pyprog.stdout.on("end", function(){
if(resultError == "") {
success(JSON.parse(result));
}else{
console.error(`Python error, you can reproduce the error with: \n${python} ${script} ${pyArgs.join(" ")}`);
const error = new Error(resultError);
console.error(error);
reject(resultError);
}
})
});
}
module.exports.callPython = callPython;
致电:
const pythonCaller = require("../core/pythonCaller");
const result = await pythonCaller.callPython("preprocessorSentiment.py", {"thekeyYouwant": value});
python:
try:
argu = json.loads(sys.argv[1])
except:
raise Exception("error while loading argument")
答案 7 :(得分:1)
/*eslint-env es6*/
/*global require*/
/*global console*/
var express = require('express');
var app = express();
// Creates a server which runs on port 3000 and
// can be accessed through localhost:3000
app.listen(3000, function() {
console.log('server running on port 3000');
} )
app.get('/name', function(req, res) {
console.log('Running');
// Use child_process.spawn method from
// child_process module and assign it
// to variable spawn
var spawn = require("child_process").spawn;
// Parameters passed in spawn -
// 1. type_of_script
// 2. list containing Path of the script
// and arguments for the script
// E.g : http://localhost:3000/name?firstname=Levente
var process = spawn('python',['apiTest.py',
req.query.firstname]);
// Takes stdout data from script which executed
// with arguments and send this data to res object
var output = '';
process.stdout.on('data', function(data) {
console.log("Sending Info")
res.end(data.toString('utf8'));
});
console.log(output);
});
这对我有用。您的python.exe必须添加到此代码段的路径变量中。另外,请确保您的python脚本位于项目文件夹中。
答案 8 :(得分:1)
许多示例已经过时多年并且涉及复杂的设置。您可以尝试一下 JSPyBridge/pythonia(完全披露:我是作者)。它是原生 JS,可让您对外部 Python 对象进行操作,就好像它们存在于 JS 中一样。实际上,它具有互操作性,因此 Python 代码可以通过回调和传递的函数返回调用 JS。
numpy + matplotlib 示例,使用 ES6 导入系统:
import { py, python } from 'pythonia'
const np = await python('numpy')
const plot = await python('matplotlib.pyplot')
// Fixing random state for reproducibility
await np.random.seed(19680801)
const [mu, sigma] = [100, 15]
// Inline expression evaluation for operator overloading
const x = await py`${mu} + ${sigma} * ${np.random.randn(10000)}`
// the histogram of the data
const [n, bins, patches] = await plot.hist$(x, 50, { density: true, facecolor: 'g', alpha: 0.75 })
console.log('Distribution', await n) // Always await for all Python access
await plot.show()
python.exit()
通过 CommonJS(没有顶级等待):
const { py, python } = require('pythonia')
async function main() {
const np = await python('numpy')
const plot = await python('matplotlib.pyplot')
...
// the rest of the code
}
main().then(() => python.exit()) // If you don't call this, the process won't quit by itself.
答案 9 :(得分:0)
答案 10 :(得分:0)
Boa可以很好地满足您的需求,请参见在JavaScript中扩展Python tensorflow keras.Sequential
类的示例。
const fs = require('fs');
const boa = require('@pipcook/boa');
const { tuple, enumerate } = boa.builtins();
const tf = boa.import('tensorflow');
const tfds = boa.import('tensorflow_datasets');
const { keras } = tf;
const { layers } = keras;
const [
[ train_data, test_data ],
info
] = tfds.load('imdb_reviews/subwords8k', boa.kwargs({
split: tuple([ tfds.Split.TRAIN, tfds.Split.TEST ]),
with_info: true,
as_supervised: true
}));
const encoder = info.features['text'].encoder;
const padded_shapes = tuple([
[ null ], tuple([])
]);
const train_batches = train_data.shuffle(1000)
.padded_batch(10, boa.kwargs({ padded_shapes }));
const test_batches = test_data.shuffle(1000)
.padded_batch(10, boa.kwargs({ padded_shapes }));
const embedding_dim = 16;
const model = keras.Sequential([
layers.Embedding(encoder.vocab_size, embedding_dim),
layers.GlobalAveragePooling1D(),
layers.Dense(16, boa.kwargs({ activation: 'relu' })),
layers.Dense(1, boa.kwargs({ activation: 'sigmoid' }))
]);
model.summary();
model.compile(boa.kwargs({
optimizer: 'adam',
loss: 'binary_crossentropy',
metrics: [ 'accuracy' ]
}));
我在另一个项目Pipcook中使用了Boa,该项目旨在解决JavaScript开发人员的机器学习问题,我们通过boa库在Python生态系统(tensorflow,keras,pytorch)上实现了ML / DL模型。