如何从Node.js调用Python函数

Gen*_*uro 156 python node.js express

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

Nev*_*Y2K 215

我所知道的最简单的方法是使用与节点一起打包的"child_process"包.

然后你可以这样做:

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

然后你要做的就是确保你import sys在python脚本中,然后你可以访问arg1使用 sys.argv[1],arg2使用 sys.argv[2]等等.

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

print(dataToSendBack)
sys.stdout.flush()
Run Code Online (Sandbox Code Playgroud)

然后节点可以使用以下方式侦听数据:

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

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

希望这很清楚.如果有需要澄清,请告诉我.

  • @ PauloS.Abreu:我对`exec`的问题是它返回一个缓冲区而不是一个流,如果你的数据超过`maxBuffer`设置,默认为200kB,你会得到一个缓冲区超出异常,你的进程是杀害.由于`spawn`使用流,因此它比`exec`更灵活. (14认同)
  • 除了打印之外,还有其他方法可以从python返回数据吗?我的 python 脚本输出了大量日志数据,显然它无法刷新所有这些数据 (4认同)
  • 只是一个小注释,如果您使用节点,您可能不应该使用process关键字 (2认同)
  • 我应该如何安装外部 pip 依赖项?我需要一个项目的 numpy 并且无法运行它,因为它没有安装它。 (2认同)
  • @javiergarval 这更适合作为新问题而不是评论。 (2认同)

Ami*_*yay 87

来自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!'))
Run Code Online (Sandbox Code Playgroud)

它不需要sysPython脚本中的模块.

以下是使用以下方法执行任务的更加模块化的方法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!'))
Run Code Online (Sandbox Code Playgroud)

  • 我很惊讶这没有得到更多的选票.虽然@ NeverForgetY2K的答案很好,但这个答案包含一个更详细的例子,包括端口监听,并很好地使用更现代的JS约定,如const和promises. (5认同)
  • 很好的例子。答应一个很好的发现我在python脚本上出现的一些错误。 (2认同)

Sou*_*hit 29

python-shell通过模块extrabacon是一个简单的方法来基本运行Node.js的从Python脚本,但高效的进程间通信和更好的错误处理.

安装: npm install python-shell.

运行一个简单的Python脚本:

var PythonShell = require('python-shell');

PythonShell.run('my_script.py', function (err) {
  if (err) throw err;
  console.log('finished');
});
Run Code Online (Sandbox Code Playgroud)

使用参数和选项运行Python脚本:

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);
});
Run Code Online (Sandbox Code Playgroud)

有关完整的文档和源代码,请查看https://github.com/extrabacon/python-shell

  • 如果您收到此错误 - TypeError: PythonShell.run is not a function 然后请确保像这样导入它 var {PythonShell} = require( 'python-shell'); (5认同)
  • 这个问题使我无法使用它-https://github.com/extrabacon/python-shell/issues/179 (2认同)

小智 14

许多示例已经过时多年并且涉及复杂的设置。您可以尝试一下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()
Run Code Online (Sandbox Code Playgroud)

通过 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.
Run Code Online (Sandbox Code Playgroud)


Geo*_*die 12

您现在可以使用支持 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);
});
Run Code Online (Sandbox Code Playgroud)

蟒蛇服务器

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()
Run Code Online (Sandbox Code Playgroud)

  • 您还可以在 Node 和 Python 端使用 https://socket.io/。 (2认同)

bor*_*mat 8

以前的大多数答案都将 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;
Run Code Online (Sandbox Code Playgroud)

称呼:

const pythonCaller = require("../core/pythonCaller");
const result = await pythonCaller.callPython("preprocessorSentiment.py", {"thekeyYouwant": value});
Run Code Online (Sandbox Code Playgroud)

Python:

try:
    argu = json.loads(sys.argv[1])
except:
    raise Exception("error while loading argument")
Run Code Online (Sandbox Code Playgroud)


1mi*_*e12 5

我在节点 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)
})
Run Code Online (Sandbox Code Playgroud)

请求.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()
Run Code Online (Sandbox Code Playgroud)

ps 不是一个人为的例子,因为节点的 http 模块没有加载我需要发出的一些请求

  • 您可能希望 python 的东西独立运行。您不需要硬编码依赖项,尤其是对于机器学习服务等更复杂的东西。如果您想向此架构添加另一部分怎么办?就像机器学习前面的缓存层,或者向机器学习模型添加额外参数的方法?运行 python 服务器也需要内存,但您可能需要灵活性。稍后您可以将这两部分分离到两台服务器 (2认同)
  • @1mike12“karl_morrison_is_a_pedant()”哈哈,喜欢它,伙计! (2认同)