Calling python script from javascript - javascript

I have the following html code (index.html):
<!DOCTYPE html>
<html>
<head>
<script>
function addParagraphText()
{
var arg1=2
var arg2=34
var arg3="john"
var myResult = runMe.py(arg1, arg2, arg3)
document.getElementById("para").innerHTML = myResult
}
</script>
</head>
<body>
<button onclick="addParagraphText();">Click me</button>
<p id="para"></p>
</html>
and the following python file runMe.py:
import sys
myArg1 = sys.argv[1]
myArg2 = sys.argv[2]
myArg3 = sys.argv[3]
# some long calculations using various libraries and modules
myOutput = '''<table style=\"border:solid;\"><tr><td> bla </td><td> lol bla <button>myButton</button> </td></tr><tr><td> blabla </td><td> blablabla </td></tr></table>'''
return myOutput
Obviously it doesn't work. What would be the easiest and quickest way to do it? I have a very long Python script that does some calculations and outputs a rather long string in html format which I would like to present after user clicks on the button. As of now, I do not need a state of the art approach, I am rather looking for a fast and easy solution.

In short: JavaScript in a html page executed by a browser cannot start the python interpreter and cannot run python scripts.
Browser security will prevent this.
You'll have to use something like XHR and cgi like in
this question. The first answer seems to be a complete example.
Otherwise try wsgi python.

Related

Google Web App and Cookies Return Undefined

I wanted to ask if it is possible to use Cookies in a Google Web App? I believe I had this working a few weeks back, but now when I try to read/write a Cookie, it is undefined.
I have tried using a jquery library, as well as doing this in javascript, but the console always returns a null or undefined response. As background, I have a Google Sheet, with a Web App attached. That app displays an HTML file.
In my document load event, I run this code:
$.cookie("test","some value");
console.log($.cookie("test"))
and the response is "undefined". If I try using vanilla javascript, like this:
document.cookie = "test=some value";
console.log(document.cookie)
then the output is a blank line.
Are cookies blocked by Google Web Apps? Or am I doing something wrong?
EDIT - I was asked to provide a minimal example. This is a basic example that still does not display cookies.
In a Google Sheet, I go to Tools-->Script Editor. Here, I have two files:
Code.js:
function doGet(e) {
output = HtmlService.createTemplateFromFile('index');
return output.evaluate();
}
index.html
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
document.cookie = "username=John Doe";
var x = document.cookie;
console.log( "Hello World" );
console.log( x );
</script>
</head>
<body>
index
</body>
</html>
When the site loads, only "Hello World" is printed to the console
Well, after some playing around with the code, it seems it has to do with securing the cookie. I am not sure if this is a new requirement (this code worked fine 2 weeks ago), but now, if I create my cookie like this:
document.cookie = "user=John; SameSite=none; secure";
It works fine.

How to extract webpage data which is generated by script using python requests

I have this html code which returns the value of PI
<!DOCTYPE html>
<html>
<body>
<p>This example calls a function which returns the value of PI:</p>
<p id="demo"></p>
<script>
function myFunction() {
return Math.PI;
}
document.getElementById("demo").innerHTML = myFunction();
</script>
</body>
</html>
When I use python requests lib, I get only the source code exactly like above but not the values of Math.PI.
I want to extract only the values of PI and how do I do using python ?
You can use js2py library from Piotr Dabkowski.
Just use a parser or a regex to get the function you want and then :
#pip install js2py
import js2py
js = """
function myFunction() {
return Math.PI;
}
"""
myFunction = js2py.eval_js(js)
myFunction()
#Returns
3.141592653589793
You need to look at the html code after it was run in a browser.
In this case using an headless browser would work. There are plenty of them to choose from, like activesoup

Call js function from python [duplicate]

I am working on a web-scraping project. One of the websites I am working with has the data coming from Javascript.
There was a suggestion on one of my earlier questions that I can directly call the Javascript from Python, but I'm not sure how to accomplish this.
For example: If a JavaScript function is defined as: add_2(var,var2)
How would I call that JavaScript function from Python?
Find a JavaScript interpreter that has Python bindings. (Try Rhino? V8? SeaMonkey?). When you have found one, it should come with examples of how to use it from python.
Python itself, however, does not include a JavaScript interpreter.
To interact with JavaScript from Python I use webkit, which is the browser renderer behind Chrome and Safari. There are Python bindings to webkit through Qt. In particular there is a function for executing JavaScript called evaluateJavaScript().
Here is a full example to execute JavaScript and extract the final HTML.
An interesting alternative I discovered recently is the Python bond module, which can be used to communicate with a NodeJs process (v8 engine).
Usage would be very similar to the pyv8 bindings, but you can directly use any NodeJs library without modification, which is a major selling point for me.
Your python code would look like this:
val = js.call('add2', var1, var2)
or even:
add2 = js.callable('add2')
val = add2(var1, var2)
Calling functions though is definitely slower than pyv8, so it greatly depends on your needs. If you need to use an npm package that does a lot of heavy-lifting, bond is great. You can even have more nodejs processes running in parallel.
But if you just need to call a bunch of JS functions (for instance, to have the same validation functions between the browser/backend), pyv8 will definitely be a lot faster.
You can eventually get the JavaScript from the page and execute it through some interpreter (such as v8 or Rhino). However, you can get a good result in a way easier way by using some functional testing tools, such as Selenium or Splinter. These solutions launch a browser and effectively load the page - it can be slow but assures that the expected browser displayed content will be available.
For example, consider the HTML document below:
<html>
<head>
<title>Test</title>
<script type="text/javascript">
function addContent(divId) {
var div = document.getElementById(divId);
div.innerHTML = '<em>My content!</em>';
}
</script>
</head>
<body>
<p>The element below will receive content</p>
<div id="mydiv" />
<script type="text/javascript">addContent('mydiv')</script>
</body>
</html>
The script below will use Splinter. Splinter will launch Firefox and after the complete load of the page it will get the content added to a div by JavaScript:
from splinter.browser import Browser
import os.path
browser = Browser()
browser.visit('file://' + os.path.realpath('test.html'))
elements = browser.find_by_css("#mydiv")
div = elements[0]
print div.value
browser.quit()
The result will be the content printed in the stdout.
You might call node through Popen.
My example how to do it
print execute('''function (args) {
var result = 0;
args.map(function (i) {
result += i;
});
return result;
}''', args=[[1, 2, 3, 4, 5]])
Hi so one possible solution would be to use ajax with flask to comunicate between javascript and python. You would run a server with flask and then open the website in a browser. This way you could run javascript functions when the website is created via pythoncode or with a button how it is done in this example.
HTML code:
<html>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
function pycall() {
$.getJSON('/pycall', {content: "content from js"},function(data) {
alert(data.result);
});
}
</script>
<button type="button" onclick="pycall()">click me</button>
</html>
Python Code:
from flask import Flask, jsonify, render_template, request
app = Flask(__name__)
def load_file(file_name):
data = None
with open(file_name, 'r') as file:
data = file.read()
return data
#app.route('/pycall')
def pycall():
content = request.args.get('content', 0, type=str)
print("call_received",content)
return jsonify(result="data from python")
#app.route('/')
def index():
return load_file("basic.html")
import webbrowser
print("opening localhost")
url = "http://127.0.0.1:5000/"
webbrowser.open(url)
app.run()
output in python:
call_received content from js
alert in browser:
data from python
This worked for me for simple js file, source:
https://www.geeksforgeeks.org/how-to-run-javascript-from-python/
pip install js2py
pip install temp
file.py
import js2py
eval_res, tempfile = js2py.run_file("scripts/dev/test.js")
tempfile.wish("GeeksforGeeks")
scripts/dev/test.js
function wish(name) {
console.log("Hello, " + name + "!")
}
Did a whole run-down of the different methods recently.
PyQt4
node.js/zombie.js
phantomjs
Phantomjs was the winner hands down, very straightforward with lots of examples.

Display the contents of a log file as it is updated

I have external programs such as ffmpeg and gstreamer running in the background and writing to a log file. I want to display the contents of this log with my Flask application, so that the user can watch the log update, like tail -f job.log would do in the terminal.
I tried to use <object data="/out.log" type="text/plain"> to point at the log file, but that failed to show the data, or the browser told me I needed a plugin.
How can I embed and update the log file in an HTML page?
Use a Flask view to continuously read from the file forever and stream the response. Use JavaScript to read from the stream and update the page. This example sends the entire file, you may want to truncate that at some point to save bandwidth and memory. This example sleeps between reads to reduce cpu load from the endless loop and allow other threads more active time.
from time import sleep
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/stream')
def stream():
def generate():
with open('job.log') as f:
while True:
yield f.read()
sleep(1)
return app.response_class(generate(), mimetype='text/plain')
app.run()
<pre id="output"></pre>
<script>
var output = document.getElementById('output');
var xhr = new XMLHttpRequest();
xhr.open('GET', '{{ url_for('stream') }}');
xhr.send();
setInterval(function() {
output.textContent = xhr.responseText;
}, 1000);
</script>
This is almost the same as this answer, which describes how to stream and parse messages, although reading from an external file forever was novel enough to be it's own answer. The code here is simpler because we don't care about parsing messages or ending the stream, just tailing the file forever.
I am using frontail package from npm.
npm i frontail -g
frontail /var/log/syslog
visit http://127.0.0.1:9001 to view logs
Source: https://github.com/mthenw/frontail
This may not be the exact answer for the question(to embed an html page), but it solves the problem of many users who are looking specifically only for
Display the contents of a log file as it is updated
For me #davidism solution (accepted answer) worked only on Firefox. It didnt work in Chrome, Brave, Vivaldi. Maybe there was some kind of de-sync in backend and frontend loops? I dont know.
Anyway i used far simpler solution, without loop on the backend and javascript loop on frontend. Maybe it's "uglier" and may cause trouble for some very long logs, but at least it works on every browser i use.
#app.route('/stream')
def stream():
with open("job.log", "r") as f:
content = f.read()
# as you see, file is loaded only once, no loop here, (loop is on frontend side)
return app.response_class(content, mimetype='text/plain')
<!DOCTYPE html>
<html>
<head>
<!-- page auto-refresh every 10 seconds -->
<meta http-equiv="refresh" content="10">
<title>Some title</title>
</head>
<body>
<h1>Log file ...</h1>
<script>
// function for adjusting iframe height to log size
function resizeIframe(obj) {
obj.style.height = obj.contentWindow.document.documentElement.scrollHeight + 'px';
}
</script>
<!-- iframe pulls whole file -->
<iframe src="{{ url_for('stream') }}" frameborder="0" style="overflow:hidden;width:100%" width="100%" frameborder="0" scrolling="no" onload="resizeIframe(this)"></iframe>
</body>
</html>
As you see the only javascript code is used to adjust iframe height to current text size.

How can I run a local Windows Application and have the output be piped into the Browser

I have Windows Application (.EXE file is written in C and built with MS-Visual Studio), that outputs ASCII text to stdout. I’m looking to enhance the ASCII text to include limited HTML with a few links. I’d like to invoke this application (.EXE File) and take the output of that application and pipe it into a Browser. This is not a one time thing, each new web page would be another run of the Local Application!
The HTML/java-script application below has worked for me to execute the application, but the output has gone into a DOS Box windows and not to pipe it into the Browser. I’d like to update this HTML Application to enable the Browser to capture that text (that is enhanced with HTML) and display it with the browser.
<body>
<script>
function go() {
w = new ActiveXObject("WScript.Shell");
w.run('C:/DL/Browser/mk_html.exe');
return true;
}
</script>
<form>
Run My Application (Window with explorer only)
<input type="button" value="Go"
onClick="return go()">
</FORM>
</body>
Have the executable listen on a port following the HTTP protocol.
Then have the web page make AJAX-style HTTP requests to the local port with JAvascript.
The executable returns text.
The web page updates itself through DOM manipulation in Javascript.
Yes, this works. It is happening 5 feet away from me right now in another cubicle.
This is called CGI
Your already using WScript to launch, it can also read StdOut.
<html>
<head>
<script type="text/javascript">
function foo() {
var WshShell = new ActiveXObject("WScript.Shell");
var oExec = WshShell.Exec("ipconfig.exe");
var input = "";
while (!oExec.StdOut.AtEndOfStream) {
input += oExec.StdOut.ReadLine() + "<br />";
}
if (input)
document.getElementById("plop").innerHTML = input;
}
</script>
</head>
<body onload="foo();">
<code id="plop"></code>
</body>
</html>
It would be easier to have your EXE create a temp file containing the HTML, then just tell Windows to open the temp HTML file in the browser.

Categories