I want to have a web page where you click a button, by using AJAX I get a string from a python script, then display that string in a paragraph HTML element.
I know I can do this by using Python, WSGI & AJAX (theoretically I can do it this way) but its waaaay too difficult. I am experienced with CGI & python.
So can I do the above using CGI?
If I can how do the python script work, exactly the same as when serving a page using CGI?
This doesn't work:
import cgitb; cgitb.enable()
import cgi
import os
print "Content-Type: text/html\n"
input_data = cgi.FieldStorage()
print "hello"
When I click my button in my page, nothing happens & my CGI server (which works fine for cgi page requests) gives me a http 501 error.
My html & javascript:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript">
<!--
function onTest( dest, params )
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById( "bb" ).innerHTML = xmlhttp.responseText;
}
}
xmlhttp.open("POST",dest,true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send( params );
}
-->
</script>
</head>
<body>
<p id="bb"> abcdef </p>
Click it
</body>
</html>
Here are 3 files [my.html, myCGI.py, myPyServer.py]. In windows XP I put them all in the same directory and double-click on myPyServer.py and things work very well.
my.html is the same as your html except:
yours: Click it
mine: Click it
myCGI.py is pretty close to yours
import cgitb; cgitb.enable()
import cgi
import os
input_data = cgi.FieldStorage()
if input_data:
print "Content-Type: text/html\n"
print "hello"
else:
f = open('my.html', 'r'); s = f.read(); f.close()
print "Content-Type: text/html\n"
print s
myPyServer.py
import CGIHTTPServer
import BaseHTTPServer
import sys
class Handler(CGIHTTPServer.CGIHTTPRequestHandler):
cgi_directories = ["/"] #make sure this is where you want it. [was "/cgi"]
PORT = 8000
httpd = BaseHTTPServer.HTTPServer(("", PORT), Handler)
# see effbot http://effbot.org/librarybook/thread.htm
def runserver():
print "serving at port", PORT
httpd.serve_forever()
import thread
thread.start_new_thread(runserver, ())
print "opening browser"
import webbrowser
url = 'http://127.0.0.1:8000/myCGI.py'
webbrowser.open_new(url)
quit = 'n'
while not(quit=='quit'):
quit = raw_input('\n ***Type "quit" and hit return to exit myPyServer.*** \n\n')
print "myPyServer will now exit."
sys.exit(0)
Of course you can use plain old CGI if you want. Your code works fine for me. (The "abcdef" turns into "hello" when the link is clicked.)
You must have some simple error in your setup. I'd check file permissions on your test scripts (a+rx), which might have been overlooked. Also I assume you've got a "#!/usr/bin/env python" (or equivalent) at the top of your cgi script (it is omitted in your example above).
Check out sajax:
http://www.modernmethod.com/sajax/
There's a python library and example in the download. You can have one CGI script that can handle your view and implement any AJAX call.
Here is one simple example using Python CGI and ajax.
http://www.ssiddique.info/writing-your-first-python-cgi-ajax-script.html
Related
I'm running Windows 7, and using Google Chrome as my web browser.
This is my code:
#!/usr/bin/env python
print 'content-type: text/html\n'
print """
<!DOCTYPE html>
<html>
<head>
<title> sample </title>
</head>
<body>
"""
print 2 + 3
print """
</body>
</html>
"""
In Command Prompt, where python results in C:\Python27\python.exe, but according to this post I should use #!/usr/bin/env python instead.
When I try to run this .py code in my browser, the source code appears instead of just 5.
If someone would provide detailed instructions as to how to properly work this, I would be most grateful.
Thanks!
Okay. So of course it is not possible to run python directly in the browser but you can configure a local server to be able to run CGI scripts. Since you are on windows you could use something like a WAMP.
Try following this tutorial
https://wiki.python.org/moin/CgiScripts
Really simple, I want to create a temporary html page that I display with the usual webbrowser.
Why does the following code produce an empty page?
import tempfile
import webbrowser
import time
with tempfile.NamedTemporaryFile('r+', suffix = '.html') as f:
f.write('<html><body><h1>Test</h1></body></html>')
webbrowser.open('file://' + f.name)
time.sleep(1) # to prevent the file from dying before displayed
Because your file doesn't exist on the disk and sits entirely in memory. That's why the browser starts but opens nothing since no code has been provided.
Try this:
#!/usr/bin/python
import tempfile
import webbrowser
tmp=tempfile.NamedTemporaryFile(delete=False)
path=tmp.name+'.html'
f=open(path, 'w')
f.write("<html><body><h1>Test</h1></body></html>")
f.close()
webbrowser.open('file://' + path)
Tested on Python 3.4.
import subprocess
import webbrowser
from http.server import BaseHTTPRequestHandler, HTTPServer
PORT = 7000
HOST = '127.0.0.1'
SERVER_ADDRESS = '{host}:{port}'.format(host=HOST, port=PORT)
FULL_SERVER_ADDRESS = 'http://' + SERVER_ADDRESS
def TemproraryHttpServer(page_content_type, raw_data):
"""
A simpe, temprorary http web server on the pure Python 3.
It has features for processing pages with a XML or HTML content.
"""
class HTTPServerRequestHandler(BaseHTTPRequestHandler):
"""
An handler of request for the server, hosting XML-pages.
"""
def do_GET(self):
"""Handle GET requests"""
# response from page
self.send_response(200)
# set up headers for pages
content_type = 'text/{0}'.format(page_content_type)
self.send_header('Content-type', content_type)
self.end_headers()
# writing data on a page
self.wfile.write(bytes(raw_data, encoding='utf'))
return
if page_content_type not in ['html', 'xml']:
raise ValueError('This server can serve only HTML or XML pages.')
page_content_type = page_content_type
# kill a process, hosted on a localhost:PORT
subprocess.call(['fuser', '-k', '{0}/tcp'.format(PORT)])
# Started creating a temprorary http server.
httpd = HTTPServer((HOST, PORT), HTTPServerRequestHandler)
# run a temprorary http server
httpd.serve_forever()
if __name__ == '__main__':
def run_xml_server():
xml_data = """
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>
"""
# open in a browser URL and see a result
webbrowser.open(FULL_SERVER_ADDRESS)
# run server
TemproraryHttpServer('xml', xml_data)
def run_html_server():
html_data = """
<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>This is a Heading</h1>
<p>This is a paragraph.</p>
</body>
</html>
"""
# open in a browser URL and see a result
webbrowser.open(FULL_SERVER_ADDRESS)
# run server
TemproraryHttpServer('html', html_data)
# choice needed server:
# run_xml_server()
# run_html_server()
Just change the file's current position.
import tempfile
import webbrowser
import time
with tempfile.NamedTemporaryFile('r+', suffix = '.html') as f:
f.write('<html><body><h1>Test</h1></body></html>')
webbrowser.open('file://' + f.name)
f.seek(0)
time.sleep(1) # to prevent the file from dying before displayed
This piece of code is an edition to the previews one and continuation of the discussion with the OP. It shows time.sleep() after webbrowser.open(). I don't think it's actually needed because the /tmp directory is emptied automatically on a regular bases by the OS but the OP commented that if he deletes the temp file via Python it is deleted before it gets fully loaded by the browser. Most likely it happens because the "browser" process is detached from this scrip which is its parent and Python doesn't wait for the process completion before executing the next statement. I though it would be clear for everyone without explanation but obviously you, guys, don't read comments.
import os, time
# ...
webbrowser.open('file://' + path)
time.sleep(1)
if os.path.exists(path):
os.remove(path)
I found this CGI Module, its letting me use HTML tags inside a python script.
ive seen some topics in here that shows how to use it, but when im using it it doesnt works.
import cgi
print ("""
<html>
<body>
Hello
</body>
</html>
""")
and this is the output when im running the script:
<html>
<body>
Hello
</body>
</html>
how can i use this properly?
thanks.
If you have your CGI script already hooked up to a web server, you will need to emit the HTTP headers too, e.g.
print("Content-Type: text/html") # HTML is following
print() # blank line, end of headers
print ("""
<html>
<body>
Hello
</body>
</html>
""")
Note that the cgi module is not being used in any way to achieve this; just simple calls to print(). The module is useful when you want to process form data submitted by a client through a HTML form.
I am new to node.js and socket.io and I am trying to write a small server that will update a webpage based on python output.
Eventually this will be used for a temperature sensor so for now I have a dummy script which prints temperature values every few seconds:
Thermostat.py
import random, time
for x in range(10):
print(str(random.randint(23,28))+" C")
time.sleep(random.uniform(0.4,5))
Here's a cut down version of the server:
Index.js
var sys = require('sys'),
spawn = require('child_process').spawn,
thermostat = spawn('python', ["thermostat.py"]),
app = require('express')(),
http = require('http').Server(app),
io = require('socket.io')(http);
thermostat.stdout.on('data', function (output) {
var temp = String(output);
console.log(temp);
io.sockets.emit('temp-update', { data: temp});
});
app.get('/', function(req, res){
res.sendFile(__dirname + '/index.html');
});
And finally the web page:
Index.html
<!doctype html>
<html>
<head>
<title>Live temperature</title>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div id="liveTemp">Loading...</div>
<script src="http://code.jquery.com/jquery-1.11.1.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
socket.on('temp-update', function (msg) {
$('#liveTemp').html(msg.data)
});
</script>
</body>
</html>
The problem is nodejs seems to recieve all of the temperature values at once, and instead of getting 10 temperature values at random intervals, I get all of the values in one long string after the script has finished:
You need to disable output buffering in python. This can be done many different ways, including:
Setting the PYTHONUNBUFFERED environment variable
Passing the -u switch to the python executable
Calling sys.stdout.flush() after each write (or print() in your case) to stdout
For Python 3.3+ you can pass flush=true to print(): print('Hello World!', flush=True)
Additionally, in your node code, (even though you have a sleep in your python code and you are now flushing stdout) you really should not assume that output in your 'data' handler for thermostat.stdout is always going to be just one line.
In the below Python CGI script, I am using javascript function for changing the picture on click. But apparently it doesn't seems to work. I am following the example from w3 schools js example. So I just want to conform, is it possible to use the javascript inside Python CGI script.
If same example has to be done in Python, what should be the approach.
#!/usr/bin/env python
import cgi
print """print "Content-type: text/html; charset=utf-8
<!DOCTYPE html>
<html>
<body>
<script>
function changeImage()
{
element=document.getElementById('myimage')
if (element.src.match("bulbon"))
{
element.src="../pic_bulboff.gif";
}
else
{
element.src="../pic_bulbon.gif";
}
}
</script>
<img id="myimage" onclick="changeImage()"
src="../pic_bulboff.gif" width="100" height="180">
<p>Click the light bulb to turn on/off the light</p>
</body>
</html>
"""
Yes, you can send javascript inside the HTML via a python CGI scrpit. You have to change the initial part of the string that you are sending to:
print """Content-type: text/html; charset=utf-8\n\n
<!DOCTYPE html>
...
EDIT to add the following comments:
There were two problems in your code:
the 1st, you had to remove the part 'print "', because you were already printing a string;
the 2nd, it is a specification of CGI that it must have "\n\n" separating the header, eg. "content-type: text/html; charset=utf-8\n\n" from the following part eg. "...", (in fact as you had one implicit "\n", it would be enough to add just one more...).