Node.js에서 Python 함수를 호출하는 방법


208

Express Node.js 응용 프로그램이 있지만 Python에서 사용할 기계 학습 알고리즘도 있습니다. 기계 학습 라이브러리의 강력한 기능을 활용하기 위해 Node.js 애플리케이션에서 Python 함수를 호출 할 수있는 방법이 있습니까?


4
node-python . 그래도 직접 사용하지는 마십시오.
univerio

22
2 년 후, node-python버려진 프로젝트 인 것 같습니다.
imrek


파이썬을 자바 스크립트로 컴파일 한 다음 호출하기위한 github.com/QQuick/Transcrypt 도 참조하십시오
Jonathan

답변:


262

내가 아는 가장 쉬운 방법은 노드와 함께 제공되는 "child_process"패키지를 사용하는 것입니다.

그런 다음 다음과 같은 작업을 수행 할 수 있습니다.

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

그런 다음 모든 당신이해야 할 메이크업은 있는지입니다 import sys파이썬 스크립트 한 다음에 액세스 할 수는 arg1사용하여 sys.argv[1], arg2사용 sys.argv[2] , 등등.

노드로 데이터를 다시 보내려면 파이썬 스크립트에서 다음을 수행하십시오.

print(dataToSendBack)
sys.stdout.flush()

그런 다음 노드는 다음을 사용하여 데이터를 청취 할 수 있습니다.

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

이렇게하면 스폰을 사용하여 여러 인수를 스크립트에 전달할 수 있으므로 인수 중 하나가 호출 할 함수를 결정하고 다른 인수는 해당 함수 등에 전달되도록 Python 스크립트를 재구성 할 수 있습니다.

이것이 분명하기를 바랍니다. 설명이 필요한지 알려주세요.


17
@ PauloS.Abreu : 내가 가진 문제 exec는 스트림 대신 버퍼를 반환하고 데이터가 maxBuffer기본 설정 인 200kB를 초과하면 버퍼 초과 예외가 발생하고 프로세스가 종료된다는 것입니다. spawn스트림을 사용 하므로 보다 유연합니다 exec.
NeverForgetY2K

2
노드를 사용한다면 프로세스 키워드를 사용하지 말아야합니다
alexvicegrab

2
외부 pip 종속성을 어떻게 설치해야합니까? 프로젝트에 numpy가 필요하며 설치되어 있지 않으므로 실행할 수 없습니다.
javiergarval

2
@javiergarval 댓글 대신 새로운 질문에 더 적합합니다.
NeverForgetY2K

3
인쇄 이외의 파이썬에서 데이터를 반환하는 다른 방법이 있습니까? 내 파이썬 스크립트는 많은 로그 데이터를 출력하고 분명히 모든 데이터를 플러시하는 데 어려움이 있습니다
lxknvlk

111

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!'))

필요하지 않습니다 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!'))

8
이것이 더 많은 표를 얻지 못한 것에 놀랐습니다. @ NeverForgetY2K의 답변은 훌륭하지만이 답변에는 포트 수신을 포함하여보다 자세한 예제가 포함되어 있으며 const & promises와 같은 최신 JS 규칙을 잘 사용합니다.
Mike Williamson

2
좋은 예입니다. 약속 하나는 내가 파이썬 스크립트에서 가지고있는 일부 오류를 감지하는 것이 좋았습니다.
htafoya 2016 년

38

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

인수 및 옵션으로 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);
});

전체 문서 및 소스 코드는 https://github.com/extrabacon/python-shell을 확인 하십시오.


3
이 문제는 그것을 사용하는 저를 중지하고 - github.com/extrabacon/python-shell/issues/179
mhlavacka

1
이 오류가 발생하면-TypeError : PythonShell.run은 함수가 아닙니다. 다음과 같이 가져 오십시오. var {PythonShell} = require ( 'python-shell');
Mohammed

4

이제 zerorpc 와 같은 Python 및 Javascript를 지원하는 RPC 라이브러리를 사용할 수 있습니다

그들의 첫 페이지에서 :

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

파이썬 서버

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

Node와 Python에서 socket.io 를 사용할 수도 있습니다 .
Bruno Gabuzomeu

3

대부분의 이전 답변은 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});

파이썬 :

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

2

노드 10과 자식 프로세스에 1.0.2있습니다. 파이썬의 데이터는 바이트 배열이며 변환해야합니다. 파이썬에서 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)
})

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

노드의 http 모듈이 내가해야 할 몇 가지 요청을로드하지 않기 때문에 ps는 고안된 예가 아닙니다.


nodejs에 서버 백엔드 빌드가 있으며 nodejs 서버에서 요청을받을 때마다 nodejs를 통해 자식 프로세스 스폰을 사용하여 생성되는 기계 학습 관련 Python 스크립트가 거의 없습니다. 이 글에서 제안한대로. 내 질문은 이것이 올바른 방법인지 또는 zmq를 사용하여 포트에 바인딩 된 플라스크 서비스처럼 파이썬 스크립트를 실행하고 nodejs 에서이 서비스에 대한 약속을 실행할 수 있는지입니다. 바로 내가 의미하는 것은 메모리 절약과 속도 절약 방법 중 어느 것입니까?
Aswin

1
파이썬 작업을 독립적으로 실행하고 싶을 것입니다. 특히 ml 서비스와 같이 복잡한 코드에 대해 하드 코드 종속성을 원하지 않습니다. 이 아키텍처에 다른 조각을 추가하려면 어떻게해야합니까? ml 앞의 캐싱 레이어처럼 또는 ml 모델에 추가 매개 변수를 추가하는 방법? 파이썬 서버를 실행하는 것은 메모리이지만 유연성이 필요할 것입니다. 나중에 두 조각을 두 서버로 분리 할 수 ​​있습니다
1mike12

그는 함수를 호출 할 수 있는지 물 었지만 질문에 대답하지 못했습니다.
K-SO의 독성이 증가하고 있습니다.

2
@ 1mike12 "karl_morrison_is_a_pedant ()"haha love it mate!
K-SO의 독성이 증가하고 있습니다.

0

파이썬을 가져 와서 번역 한 다음 자바 스크립트처럼 호출 할 수 있습니다. 나는 이것을 screeps를 위해 성공적으로 해왔고 심지어 브라우저에서 la brython 으로 실행되도록했다 .


0
/*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를 추가해야합니다. 또한 파이썬 스크립트가 프로젝트 폴더에 있는지 확인하십시오.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.