Node.js'den bir Python işlevi nasıl çağrılır


208

Express Node.js uygulamam var, ancak Python'da kullanmak için bir makine öğrenme algoritması da var. Makine öğrenimi kitaplıklarının gücünü kullanmak için Node.js uygulamamdan Python işlevlerini çağırabileceğim bir yol var mı?


4
düğüm-python . Yine de hiç kullanmadım.
univerio

22
İki yıl sonra, node-pythonterk edilmiş bir proje gibi görünüyor.
imrek


Ayrıca bkz. Pithhon'u javascript'e derlemek ve sonra çağırmak için github.com/QQuick/Transcrypt
Jonathan

Yanıtlar:


262

Bildiğim en kolay yol, düğümle birlikte gelen "child_process" paketini kullanmaktır.

Sonra şöyle bir şey yapabilirsiniz:

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

Sonra tek yapmanız gereken import syspython betiğinizde olduğunuzdan emin olmaktır ve daha sonra arg1kullanarak sys.argv[1], arg2kullanarak sys.argv[2], vb. Erişebilirsiniz.

Verileri düğüme geri göndermek için sadece python betiğinde aşağıdakileri yapın:

print(dataToSendBack)
sys.stdout.flush()

Ve sonra düğüm aşağıdakileri kullanarak verileri dinleyebilir:

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

Bu, spawn kullanarak bir komut dosyasına birden çok bağımsız değişkenin aktarılmasına izin verdiğinden, bağımsız değişkenlerden birinin hangi işlevi çağıracağına karar vermesi ve diğer bağımsız değişken bu işleve geçirilmesi için bir python komut dosyasını yeniden yapılandırabilirsiniz.

Umarım bu açıktı. Bir şeyin açıklığa ihtiyacı varsa bana bildirin.


17
@ PauloS.Abreu: Sahip olduğum sorun exec, akış yerine bir arabellek döndürmesi ve verileriniz maxBuffer200kB'ye varsayılan ayarı aşarsa, bir arabellek aşıldı ve işleminiz öldürüldü. İtibaren spawnkullanımları akışları, bu daha esnektir exec.
NeverForgetY2K

2
Sadece küçük bir not, eğer düğüm kullanırsanız muhtemelen süreç anahtar sözcüğünü kullanmamalısınız
alexvicegrab

2
Harici pip bağımlılıklarını nasıl kurmalıyım? Bir proje için numpy gerekir ve yüklü olmadığı için çalıştıramazsınız.
javiergarval

2
@javiergarval Bu yorum yerine yeni bir soru olarak daha uygun olacaktır.
NeverForgetY2K

3
Python'dan yazdırma dışında veri döndürmenin başka bir yolu var mı? Python
betiğim

112

Python geçmişinden gelen ve makine öğrenme modellerini Node.js uygulamasına entegre etmek isteyen insanlar için örnek :

child_processÇekirdek modülü kullanır :

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

sysPython betiğinizde modül gerektirmez .

Aşağıda, görevi kullanarak görevi gerçekleştirmenin daha modüler bir yolu verilmiştir 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
Bunun daha fazla oy almamasına şaşırdım. @ NeverForgetY2K'nın cevabı iyi olsa da, bu cevap port dinleme de dahil olmak üzere daha ayrıntılı bir örnek içeriyor ve const & promises gibi daha modern JS kurallarını güzel bir şekilde kullanıyor.
Mike Williamson

2
Harika bir örnek. Söz bir python komut dosyası vardı bazı hataları tespit etmek için iyi oldu.
htafoya

38

python-shellTarafından modül extrabacontemel ile node.js gelen Python komut dosyalarını çalıştırmak için basit bir yoldur, ancak verimli süreçler arası iletişim ve daha iyi hata işleme.

Kurulum: npm install python-shell .

Basit bir Python betiği çalıştırma:

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

PythonShell.run('my_script.py', function (err) {
  if (err) throw err;
  console.log('finished');
});

Argüman ve seçeneklerle bir Python betiği çalıştırma:

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

Tüm dokümantasyon ve kaynak kodu için https://github.com/extrabacon/python-shell adresini ziyaret edin


3
Bu sorun beni kullanmama engel
mhlavacka

1
Bu hatayı alıyorsanız - TypeError: PythonShell.run bir işlev değildir Sonra bu şekilde aldığınızdan emin olun var {PythonShell} = requir ('python-shell');
Muhammed

4

Artık python ve zerorpc gibi Javascript'i destekleyen RPC kitaplıklarını kullanabilirsiniz

Ön sayfalarından:

Node.js İstemcisi

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 Sunucusu

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

Hem Düğüm hem de Python tarafında socket.io öğesini de kullanabilirsiniz .
Bruno Gabuzomeu

3

Önceki cevapların çoğu on ("veri") içindeki sözün başarısını çağırır, bunu yapmak için uygun bir yol değildir çünkü çok fazla veri alırsanız sadece ilk kısmı alırsınız. Bunun yerine son olayda yapmanız gerekir.

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;

Aramak:

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

piton:

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

2

Düğüm 10 ve alt süreçteyim 1.0.2. Python'dan gelen veriler bir bayt dizisidir ve dönüştürülmesi gerekir. Python'da bir http isteği yapmak için başka bir hızlı örnek.

düğüm

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

ps düğümün http modülü yapmam gereken birkaç istek yüklemediğinden, anlaşılmaz bir örnek değil


Nodejs üzerinde bir sunucu arka uç inşa var ve ben ne zaman benim nodejs sunucusunda istek aldığımda çocuk süreci spade nodejs aracılığıyla spawn kullanarak yumurtlama birkaç makine öğrenme ilgili python komut dosyaları var. Bu konuda önerildiği gibi. Benim sorum, bunu yapmanın doğru yolu ya da python betiğimin zmq kullanarak bir bağlantı noktasına bağlanan ve nodejs'den bu hizmete bir söz verebilecek bir flask hizmeti gibi çalıştırabilmem. Demek istediğim, bellek tasarrufu ve hız tasarrufu yöntemi hangi yolla?
Aswin

1
Muhtemelen python şeylerinin bağımsız çalışmasını istiyorsunuz. Sabit kod bağımlılıkları istemezsiniz, özellikle de bir ml hizmeti olarak daha karmaşık bir şey için. Ya bu mimariye başka bir parça daha eklemek isteseydiniz? ML'nin önündeki bir önbellek katmanı veya ml modeline ekstra parametreler eklemenin bir yolu gibi mi? Ayrıca bir python sunucusu çalıştırmak için bellek, ama muhtemelen esnekliğe ihtiyacınız olacak. Daha sonra iki parçayı iki sunucuya
ayırabilirsiniz

Bir fonksiyon çağırabileceğini sordu , bu soruya cevap vermiyor.
K - SO'da toksisite artıyor.

2
@ 1mike12 "karl_morrison_is_a_pedant ()" haha ​​love it dostum!
K - SO'da toksisite artıyor.


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

Bu benim için çalıştı. Bu kod pasajı için python.exe dosyanızın yol değişkenlerine eklenmesi gerekir. Ayrıca, python betiğinizin proje klasörünüzde olduğundan emin olun.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.