我有一个Express Node.js应用程序,但我也有一个机器学习算法在Python中使用。是否有一种方法可以从我的Node.js应用程序调用Python函数来利用机器学习库的强大功能?


当前回答

我在节点10和子进程1.0.2上。来自python的数据是一个字节数组,必须进行转换。这是另一个用python发出http请求的快速示例。

node

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)
})

request.py

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模块不加载我需要做的一些请求

其他回答

我知道的最简单的方法是使用“child_process”包,它随node一起打包。

然后你可以这样做:

const spawn = require("child_process").spawn;
const pythonProcess = spawn('python',["path/to/script.py", arg1, arg2, ...]);

然后你要做的就是确保你在python脚本中导入了sys,然后你就可以使用sys访问arg1了。Argv [1], arg2使用sys。Argv[2],等等。

要将数据发送回节点,只需在python脚本中执行以下操作:

print(dataToSendBack)
sys.stdout.flush()

然后node可以使用以下命令监听数据:

pythonProcess.stdout.on('data', (data) => {
 // Do something with the data returned from python script
});

由于这允许使用spawn将多个参数传递给脚本,您可以重新构造python脚本,以便其中一个参数决定调用哪个函数,而另一个参数传递给该函数,等等。

希望这是清楚的。如果有需要澄清的地方请告诉我。

我在节点10和子进程1.0.2上。来自python的数据是一个字节数组,必须进行转换。这是另一个用python发出http请求的快速示例。

node

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)
})

request.py

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模块不加载我需要做的一些请求

之前的大多数答案都将承诺的成功称为on(“数据”),这不是正确的方法,因为如果你收到很多数据,你只会得到第一部分。相反,你必须在end事件上做。

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")

许多例子都是过时的,并且涉及复杂的设置。您可以尝试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(没有顶级await):

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.

您现在可以使用支持Python和Javascript的RPC库,例如zerorpc

从他们的头版:

node . js的客户

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);
});

Python服务器

import zerorpc

class HelloRPC(object):
    def hello(self, name):
        return "Hello, %s" % name

s = zerorpc.Server(HelloRPC())
s.bind("tcp://0.0.0.0:4242")
s.run()