I want Nodejs to run a Python script in a new terminal.
I have a python script named test.py which simply does print('Hello World')
However, when I enter localhost:8080/python_run/ in my browser, I do not know if the script is run.
I can know the output using python.stdout.on('data', (data) => {console.log(`stdout: ${data}`);})
but I want to be able to monitor a large complex python script running which would give many print statements throughout.
I want it to display in a separate terminal instead of seeing only the std.out in the nodejs terminal.
I also wish to only implement these using vanilla nodejs.
The spawn child process of nodejs does not seem to let me run in a separate terminal.
How can I trigger a long complex and probably resource intensive Python script to run with the nodejs server as long as it receives a request (GET request of the url in this case)? If possible I'd also want the Python script to communicate back to the nodejs server once the Python script has finished running, to trigger some change of display of a website.
My current code
const {parse} = require('querystring');
const http = require('http');
const path = require('path');
const fs = require('fs');
var url = require("url");
const {spawn} = require('child_process');
const spawn1 = require('child_process').exec;
const requestHandler = (req, res) => {
fs.readFile("index_noexp.html",(err, data) => {
if(!err) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data);
}
});
if (/python_run/i.test(req.url)) {
console.log('Now running the dangerous python script');
try {
const { spawn } = require('node:child_process');
var python = spawn('python', ['/Users/damian/nodetest/test.py']);
// var python = spawn1('python', [__dirname + '/test.py']);
python.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
})
} catch (error) {
console.error(error);
} finally {
console.log('Not sure what happened');
}
}
const server = http.createServer(requestHandler);
server.listen(8080);
Related
const express = require('express')
const {spawn} = require('child_process');
const app = express()
const port = 8000
app.get('/', (req, res) => {
var dataToSend;
const python = spawn('python', ['script.py']);
python.stdout.on('data', function (data) {
console.log('Pipe data from python script ...');
dataToSend = data.toString();
});
python.on('close', (code) => {
console.log(`child process close all stdio with code ${code}`);
res.send(dataToSend)
});
})
app.listen(port, () => console.log(`Example app listening on port
${port}!`))
This is my index.js file and when I try to run a python script from it, it works only for code that is written before import part in python script. When i run python script individually it runs perfect but not from js file. why ?
I am developing a web application that will use python model.I have created environment for python model as well.But the problem i am facing is i have no idea how to execute that python environment through node js because i am using node.js at backend.
you can run python virtual environment inside nodejs, you need call python environment from bin directory where you install python virtual environment, and then you can use child_process for run python code inside nodejs, see this example:
const express = require('express')
const app = express()
app.get('/', (req, res) => {
const { spawn } = require('child_process');
const pyProg = spawn('~/py3env/bin/python', ['test.py']);
pyProg.stdout.on('data', function(data) {
console.log(data.toString());
res.write(data);
res.end('end');
});
})
app.listen(3000, () => console.log('listening on port 3000'))
even you can excecute command line with shelljs, and in this moment you can run pm2: see this:
const shell = require('shelljs');
shell.exec('pm2 start test.py --interpreter=./py3env/bin/python', function(code, output) {
console.log('Exit code:', code);
console.log('Program output:', output);
});
After you setting your python virtual enironment, You can use PythonShell in node js
Firstly install PythonShell to your project by this command
npm install python-shell --save
then you can call python script in your js file by the following
const path = require('path');
const { PythonShell } = require("python-shell");
// this is your current folder
const py_path = path.join(__dirname, '');
// this is your folder with python environment in it
const python_exe_path = path.join(__dirname, 'python_env/scripts/python.exe');
// then create your python shell options
const py_shell_options = {
mode: 'text',
pythonPath: python_exe_path,
pythonOptions: ['-u'], // get print results in real-time
scriptPath: py_path
// args: ['value1', 'value2', 'value3']
};
// now you can initialize your shell and ready to use it
const pyshell = new PythonShell('py_scripts/my_script.py', py_shell_options);
// sends a message to the Python script via stdin
pyshell.send('hello');
pyshell.on('message', function (message) {
// received a message sent from the Python script (a simple "print" statement)
console.log(message);
});
// end the input stream and allow the process to exit
pyshell.end(function (err,code,signal) {
if (err) throw err;
console.log('The exit code was: ' + code);
console.log('The exit signal was: ' + signal);
console.log('finished');
});
That it, please read more about PythonShell from the official site
I'm writing a simple web app to get a handle on how node child processes work. Basically you enter your name into an angular frontend which passes the name to an express backend in a javascript object. The backend passes the name as an argument to a simple python script as a command line argument using the child_process module. Theres nothing wrong with the front end and the name gets successfully passed to the backend but when I call stdout on the python process it doesn't work. There aren't any error messages.
Heres the express code:
app.post('/api', (req, res, next) => {
console.log(req.body.name);
const spawn = require('child_process').spawn;
const process = spawn('python3', ['./hello.py', req.body.name]);
process.stdout.on('data', (data) => {
console.log(data);
res.status(200).json({greeting: data});
});
});
I put two console.log statements in the code to debug it. The first one prints the data but the second one inside the stdout function isn't called at all. The python script is in the same folder as the app.js express file so I'm pretty sure theres nothing wrong with the file path.
Here's the python script:
import sys
print('hello' + sys.argv[1])
sys.stdout.flush()
When I run it in the command line it works exactly as expected but I included it anyway just in case.
Process.stdout.on will keep on streaming until the end event. The code is wrong because you are actually sending response for every time there is some value in stdout. And you cant set the response header more than once. Try writing the code in below way. Thanks
let output;
Process.stdout.on("data", (data) => {
output += data;
});
Process.on("end", () => {
// send response here
});
close will trigger when your data completes
app.get("/list-account", async (req, res) => {
try {
let array = "";
let response = await child.spawn(
path.join(__dirname, "xcv-alpha-keychain.exe"),
["listaccounts"]
);
await response.stdout.on("data", (data) => {
const stdout = data.toString();
console.log("stdout", stdout);
array += stdout;
// return res.status(200).json({ array });
});
response.stderr.on("data", (data) => {
return res.status(500).send(data.toString());
});
response.on("error", (error) => {
return res.status(500).send({ error });
});
response.on("close", (code) => {
return res.status(200).json({ array, code });
});
} catch (error) {
return res.status(500).send(["a", "b", "c"]);
}
});
Instead of
console.log(data)
use
console.log(data.toString())
With below code I have created a HTTP server on port 3000 and have added some get parameters. I want to invoke a python script with this express.js server code such that when I hit localhost:3000/key1/abc/key2/234 python script will get invoked. I've my python script ready which takes input args as sys.argv. Please suggest how to call python script with this code so that it will take value1 and value 2 as input arguments and return json.
var express = require('express');
var app = express();
app.get('/key1/:value1/key2/:value2',function(req,res)
{
console.log(req.params);
var value1 = req.params.value1;
var value2 = req.params.value2;
res.send(req.params);
});
app.listen(3000,function()
{
console.log("Server listening on port 3000");
});
To run a Python script from Node.js would require spawning a new process.
You can do that with child_process.
You would run python as the executable and give your script name as the first argument.
Here is an example based on the documentation linked above:
const spawn = require('child_process').spawn;
const ls = spawn('python', ['script.py', 'arg1', 'arg2']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.log(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
If you want to execute it with params
const scriptExecution = spawn(pythonExecutable, ["my_Script.py", "Argument 1","Argument 2"]);
I am trying to host a local server (using Node.js) on a Raspberry Pi. The Pi has an ADC (MCP3008) connected to it, and I have a Python script that continuously samples the ADC and prints the current value. I want to have the Node server run the Python script, and whenever it sees a print statement, to just do a console.log(current value) for the time being. I am new to Node and web development in general, so it may be something simple that I'm missing so that Node will continuously receive data from the Python script. I'm trying to use Socket.io at the moment, as that seems to make sense as the method for Node to see changes from the Python script, but maybe this isn't the best way to do it. The basic webpage is from a tutorial I found (http://www.jaredwolff.com/blog/raspberry-pi-getting-interactive-with-your-server-using-websockets/). The code I am currently using is here:
var app = require('http').createServer(handler)
, io = require('socket.io').listen(app)
, url= require('url')
, fs = require('fs')
, gpio = require('onoff').Gpio
, PythonShell = require('python-shell');
app.listen(5000);
function handler (req, res) {
var path = url.parse(req.url).pathname;
if (path == '/') {
index = fs.readFile(__dirname+'/public/index.html',
function(error,data) {
if (error) {
res.writeHead(500);
return res.end("Error: unable to load index.html");
}
res.writeHead(200,{'Content-Type': 'text/html'});
res.end(data);
});
} else if( /\.(js)$/.test(path) ) {
index = fs.readFile(__dirname+'/public'+path,
function(error,data) {
if (error) {
res.writeHead(500);
return res.end("Error: unable to load " + path);
}
res.writeHead(200,{'Content-Type': 'text/plain'});
res.end(data);
});
} else {
res.writeHead(404);
res.end("Error: 404 - File not found.");
}
}
// Python
var pyshell = new PythonShell('mcp3008.py');
pyshell.run('mcp3008.py', function (err, results) {
if (err) throw err;
console.log('Results: %j', results);
});
io.sockets.on('connection', function (socket) {
pyshell.on('message', function (message) {
console.log(message);
});
});
Thank you for any hints or help that you can provide!
As jfriend00 recommended, I looked into node.js solutions. I had previously tried this, using several mcp3008 packages available on npm, but none of them successfully installed on my Raspberry Pi (model B). However, I ended up rewriting the one located here (https://github.com/fiskeben/mcp3008.js) as a separate .js file, included it with my code (along with some work from the npm spi library), and put it into a loop to read the ADC pin. That's working for now, and should be good enough for my current needs, but it still seems like a more processor-intensive solution than it should be. Thanks for your feedback!