How can I run python script in node.js project - python

What I want to do:
I would want to create 2 endpoints /servers and /items. Both endpoints should send json from GET request, but for /servers endpoint, I have python script that scrapes data from the website and outputs json file and here is a problem, because I can't run this python script as I don't have required imports and don't really know how to add them using node.js.
server.js
const app = require('express')();
const { dirname } = require('path');
const appDir = dirname(require.main.filename);
const fs = require('fs');
const { exec } = require('child_process');
const { PythonShell } = require('python-shell');
const PORT = 8080;
const options = {
pythonPath: process.env.PYTHONPATH
};
app.get('/servers', (req, res) => {
// Run the serversScrapper.py script and update the serversList.json file
PythonShell.run(`${appDir}/serverScrapper.py`, options, (err, results) => {
if (err) {
console.error(err);
res.sendStatus(500);
return;
}
// Send the updated serversList.json file as the response
res.sendFile(`${appDir}/serversList.json`, (err) => {
if (err) {
res.status(500).send(err);
}
});
});
});
app.get('/items', (req, res) => {
res.sendFile(`${appDir}/itemsList.json`, (err) => {
if (err) {
res.status(500).send(err);
}
});
});
// Run the script every 2 minutes
setInterval(() => {
PythonShell.run(`${appDir}/serverScrapper.py`, null, (err, results) => {
if (err) {
console.error(err);
}
});
}, 2 * 60 * 1000);
app.listen(PORT, () => console.log('Server up at 8000'))
I've copied and pasted only script file to the project folder, so that might be an issue, but I think there should be a way for node.js to automatically start python script and import required libraries (bs4, requests, json)
error log:
PythonShellError: ModuleNotFoundError: No module named 'bs4'
at PythonShell.parseError (/rbd/pnpm-volume/eb08c55a-3afc-4775-99f3-8543de0493fc/node_modules/python-shell/index.js:295:21)
at terminateIfNeeded (/rbd/pnpm-volume/eb08c55a-3afc-4775-99f3-8543de0493fc/node_modules/python-shell/index.js:190:32)
at ChildProcess.<anonymous> (/rbd/pnpm-volume/eb08c55a-3afc-4775-99f3-8543de0493fc/node_modules/python-shell/index.js:182:13)
at ChildProcess.emit (events.js:400:28)
at Process.ChildProcess._handle.onexit (internal/child_process.js:282:12)
----- Python Traceback -----
File "/app/serverScrapper.py", line 2, in <module>
from bs4 import BeautifulSoup {
traceback: 'Traceback (most recent call last):\n' +
' File "/app/serverScrapper.py", line 2, in <module>\n' +
' from bs4 import BeautifulSoup\n' +
"ModuleNotFoundError: No module named 'bs4'\n",
executable: 'python3',
options: null,
script: '/app/serverScrapper.py',
args: null,
exitCode: 1
}

Related

is there any method how to call python file from node.js

this is my first time using stackoverflow asking questions
so my problem is i don't know how can i call these python files to execute from index.js file
technically i want to call python files after i press submit button
our web page output
and this is my code structure in index.js
const express = require("express")
const path = require("path")
const multer = require("multer")
const app = express()
//Call python script
const { spawn } = require('child_process');
const testing = spawn('python', ['test.py']);
testing.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
filename: function (req, file, cb) {
console.log(file.mimetype);
if(file.mimetype == "video/mp4"){
cb(null, file.fieldname + "-" + Date.now()+".mp4")
}
else cb(null, file.fieldname + "-" + Date.now()+".jpg")
}
})
app.post("/uploadFile",function (req, res, next) {
// Error MiddleWare for multer file upload, so if any
// error occurs, the image would not be uploaded!
upload(req,res,function(err) {
if(err) {
// ERROR occured (here it can be occured due
// to uploading image of size greater than
// 1MB or uploading different file type)
res.send(err)
}
else {
// SUCCESS, image successfully uploaded
res.send("Success, your file has been uploaded!")
}
})
})
// Take any port number of your choice which
// is not taken by any other process
app.listen(8080,function(error) {
if(error) throw error
console.log("Server created Successfully on PORT 8080")
})

Running a Python script from Node.js returns blank

I'm following the posts here but when I go to localhost:3000, the page is blank. I've tried to change my Python script path but that does not seem to work. It seems that it's not accessing the script1.py file. I'm not sure why.
NOTE: script1.py and index.js are both in the same directory.
Here is my index.js:
const express = require('express');
const {spawn} = require('child_process');
const app = express();
const port = 3000;
app.get('/', (req, res) => {
var dataToSend;
const python = spawn('python', ['script1.py']);
python.stdout.on('data', function (data) {
dataToSend = data.toString();
});
python.on('close', (code) => {
console.log(`child process close all stdio with code ${code}`);
res.send(dataToSend)
});
});
app.listen(port);
Here is my script1.py:
print('Hello from python')
And http://localhost:3000/ is completely blank (though it is being run) but it's not displaying 'Hello from python'.
this is how it worked for me:
app.js file:
const spawn = require("child_process").spawn;
const pythonProcess = spawn('python', ["./p1.py"]);
const http = require('http');
let pythonData = null;
pythonProcess.stdout.on('data', (data) => {
pythonData = data.toString();
});
let app = http.createServer((req, res) => {
// Set a response type of plain text for the response
if(req.url === "/getPyt") {
res.end(JSON.stringify(pythonData));
}
if(req.url === "/") {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end("Hello there");
}
});
// Start the server on port 3000
app.listen(3000, 'localhost');
console.log('Node server running on port 3000');
p1.py :
import sys
print("Hello there")
sys.stdout.flush()
I think what you missed is that ./ refferencing python file.
I've commented sys.stdout.flush() inside p1.py and it's also working.

Call a Python script from React with next routing and a node.js server

I am working on an ethereum application that uses react, next-routing and a basic node.js server. I want to run a python script on a specific route, claimAnalysis to be specific, in order to perform some predictions. I want the script to be executed every time I visit the claimAnalysis route.
server.js
const express = require("express")();
const next = require("next");
const app = next({
dev: process.env.NODE_ENV !== "production"
});
const routes = require("./routes");
const handler = routes.getRequestHandler(app);
app.prepare().then(() => {
const server = express.use(handler);
server.listen(3000, (err) => {
if(err) throw err;
console.log("Server ready on localhost:3000");
});
});
routes.js
const routes = require("next-routes")();
routes
.add("/insurance/new", "/insurance/new")
.add("/insurance/:address", "/insurance/show")
.add("/insurance/:address/claims", "/insurance/claims/index")
.add("/insurance/:address/claims/new", "/insurance/claims/new")
.add("/insurance/:address/claims/:id/claimAnalysis", "/insurance/claims/claimAnalysis");
module.exports = routes;
Please guide me if I can call a function from the claimAnalysis.js file that runs the python script.
If you're using Node 10+, you can use util.promisify to execute your python scriptwhich returns a Promise<{ stdout, stderr }> object. See an example below:
const util = require('util');
const exec = util.promisify(require('child_process').exec);
// function to execute python script
async function executeScript(path) {
try {
const { stdout, stderr } = await exec(`python3 ${path}`);
console.log('stdout:', stdout);
console.log('stderr:', stderr);
} catch (e) {
console.error(e);
}
}
Now let's use the function in your route:
app.get('/insurance/claims/claimAnalysis', async function (req, res) {
await executeScript();
res.send('claimAnalysis request completed');
...
})
You can use "child_process" to finish function.
You can see this example:
const path = require('path')
const {spawn} = require('child_process')
/**
* Run python myscript, pass in `-u` to not buffer console output
* #return {ChildProcess}
*/
function runScript(){
return spawn('python', [
"-u",
path.join(__dirname, 'myscript.py'),
"--foo", "some value for foo",
]);
}
const subprocess = runScript()
// print output of script
subprocess.stdout.on('data', (data) => {
console.log(`data:${data}`);
});
subprocess.stderr.on('data', (data) => {
console.log(`error:${data}`);
});
subprocess.stderr.on('close', () => {
console.log("Closed");
});

NodeJs: Get output of python-shell to send back to client

I am trying to create a website where a user can submit python code, it gets sent to my server to be executed and I send back the results to the client. Currently I am using a NodeJs server and need to run the python code from there. To do this, I am using Python-shell like so:
const runPy = async (code) => {
const options = {
mode: 'text',
pythonOptions: ['-u'],
scriptPath: path.join(__dirname, '../'),
args: [code],
};
const result = await PythonShell.run('script.py', options, (err, results) => {
if (err) throw err;
return results; <----- HOW DO I RETURN THIS
});
console.log(result.stdout);
return result;
};
I understand I can console.log() the results in the PythonShell.run() but is there a way to return the results from my runPy function to then be manipulated and sent back to the client?
It looks from the python-shell documentation that the PythonShell.run method doesn't have an async mode. So, one option is to wrap it in a promise:
const runPy = async (code) => {
const options = {
mode: 'text',
pythonOptions: ['-u'],
scriptPath: path.join(__dirname, '../'),
args: [code],
};
// wrap it in a promise, and `await` the result
const result = await new Promise((resolve, reject) => {
PythonShell.run('script.py', options, (err, results) => {
if (err) return reject(err);
return resolve(results);
});
});
console.log(result.stdout);
return result;
};

Best way to insert 10,000 JSON files (total 30GB) into MongoDB

It doesn't look to me that using python to combine all the json files is convenient, and the combined file would be 30G.
I am using mongoDB and nodejs. The way how I populate a sample json is:
var data = require('./data1.json')
var populateDB = function() {
db.collection('temp', function(err, collection) {
collection.insert(data, {safe:true}, function(err, result) {});
});
};
This only adds one json file. How should I populate the collection with the 10000+ json files from here? any suggestion is highly appreciated!
The easiest way would be to write a Node program that processes one JSON file and then run it multiple time from the shell:
for i in *.json; do node program.js $i; done
Your Node program would just need to access the name from process.argv instead of having it hardcoded but the logic would be the same.
If you want to do everything in node then you will have to read the directory, get all .json files, read every one of them in sequence and then run a code similar to the one you posted. If it's a one off task then you can even get away with using the "Sync" functions to simplify your code if it's a sequential task to do one thing at a time and you don't care about adding the data in parallel.
Something like this would work
npm i glob-fs mongodb async --save
const async = require('async');
const fs = require('fs');
const glob = require('glob-fs')({ gitignore: true });
const MongoClient = require('mongodb').MongoClient;
const files = './files/data*.json';
const collection = 'test';
const url = 'mongodb://localhost:27017/test';
// Connect to db
MongoClient.connect(url, function (err, db) {
if (err) {
console.log(err);
}
// Get the collection
const col = db.collection(collection);
glob.readdirPromise(files)
.then(function (f) {
return async.eachSeries(f, (item, callback) => {
fs.readFile(item, 'utf8', function (err, data) {
if (err) {
return console.log(err);
}
// Insert into mongo
col.insertMany(JSON.parse(data)).then((r) => {
console.log(r);
return callback(r);
}).catch(function (fail) {
console.log(fail)
});
});
}, err => {
console.log(err);
});
})
.then(err => {
if (err) {
db.close();
}
})
.catch(err => {
console.log(err);
});
});

Categories

Resources