Python CGI URL Redirect - python

I am currently writing a CGI python script. Once I have time I will rewrite this in web2py, but simply have no time ATM for this.
I have the whole logic built, except for one thing. I need to be able to:
1) Send a variable to start a process (got that it works)
2) Refresh the page until such process ends
3) display information once process is done.
I can't seem to be able to get passed the URL refresh part, and stripping the variable which started the original process.
I tried webbrowser (webbrowser.open('http://example.com?running=1')), however for some reason I am not being redirected at all on Mac.
if print_html.parse_url():
url_variable=print_html.parse_url()
IP=url_variable['IP'].value
Iterations=int(url_variable['quantity'].value)
start=url_variable['start'].value
refresh=url_variable['refresh'].value
if start == "1":
As you can see I read the variables from URL, and assign values. When start == '1' I want to start running the rest of the programs. While the program is running I want to change the URL variable to re-read the page until everything is finished processing
Some more clarification, perhaps this helps:
I need to refresh the page, or perhaps open the same page but with different variables.
For instance
1st instance: http://example.com/test.py?start=1
logic runs and then refresh spawning:
2st instance: http://example.com/test.py?running=1
Does that make sense?

You can refresh the page using the HTML meta http-equiv directive.
#!/usr/bin/python
import datetime
import time
print "Content-Type: text/html"
print ""
print '''
<html>
<head>
<meta http-equiv="refresh" content="15" />
</head>'''
now = datetime.datetime.now()
now = now.isoformat()
print '''
<body>
The time is now %s
</body>''' % now

Related

Get user input via for loop for python script in a Flask application

I am trying to create a very simple one-page Flask application for a python script that I have. The script requires multiple user inputs in a for-loop with the number of loops being user input as well.
Here is the code in my script to make it more clear:
def shared_books():
import requests as re
from bs4 import BeautifulSoup
import time
num_lists = int(input('Enter the number of lists you would like to search:'))
urls = []
page_counts = []
for i in range(num_lists):
urls.append(input(f'Enter the url for list {i + 1}:'))
page_counts.append(int(input(f'Enter the number of pages for list {i + 1}:')))
I want a simple HTML that will ask the user for the number of lists, then the URL and page count for each list as is shown in my function. Then it will run the entire function.
The HTML code I have right now is super simple and I don't want much else outside of the input parts:
<html>
<head>
<title>Goodreads-App</title>
</head>
<body>
<h1>Welcome to my app!</h1>
<<p>This app will allow you to see books that are
shared between multiple lists on goodreads</p>
</body>
</html>
Please let me know how I can set up this application!
Firstly, I suggest you take a look at the Flask docs. You are doing it right in terms of having a view function, but the input() python keyword doesn't work like that in Flask. Instead, you should render an html template which you can then put your form input field into. Here is an example:
from flask import Flask, render_template
#flask initialising stuff, read docs for info
#app.route("/home")
def home():
return render_template("home.html")
Flask runs on your computer's local server "localhost", which is not publicly accessible. It conventionally runs on port 5000, which gives the name "localhost:5000".
When someone visits "localhost:5000/home", flask will look for a file called "home.html" in a pre-designated templates folder – the default is a directory called "templates" which you should put your html files into.
So if this is your "home.html" file:
<html>
<head>
<title>Goodreads-App</title>
</head>
<body>
<h1>Welcome to my app!</h1>
<p>This app will allow you to see books that are
shared between multiple lists on goodreads</p>
</body>
</html>
When you load the page associated with a specific function, it will return a template which is rendered as html. The above should look something like this:
And that is how to start.
Thank you for the answers! I haven't quite solved the previous issue but have approached it from a different angle which is working now! I will potentially post again if I don't solve it.
I am using flask forms to do what I was trying.

how to send response to html using cgi python script

I am trying to design and implement a basic calculator in HTML and Python(using CGI). Below given is a static HTML web page and it is being redirected to a python script (calci.py) where, I am able to calculate the sum but unable to append the resultant to the 'output' textbox.
calculator.html
<html>
<head>
<title>Calculator</title>
</head>
<body>
<form action="python_scripts/calci.py" method="post">
Input 1 : <input type="text" name="input1"/><br>
Input 2 : <input type="text" name="input2"/><br>
<input type="submit" value="+" title="add" /><br>
output : <input type="text" name="output"/><br>
</form>
</body>
</html>
calci.py
import cgi
form = cgi.FieldStorage()
input1 = form.getvalue('input1')
input2 = form.getvalue('input2')
output = str(int(input1)+int(input2))
#how to return the response to the html
#and append it to the textbox
Thanks
This is not the way Web applications work - not hat simply, at least.
If you want to rely only on the browser, and plain HTML for your application, each request has to send the whole html page as a string. You have to use Python's string formatting capabilities to put the resulting number in the correct place in the HTML form.
This way of working is typical of "Web 1.0" applications (as opposed to the "Web 2.0" term used about ten years ago).
Modern web applications use logic that runs on the client side, in Javascript code, to make an HTTP request to retrieve only the needed data - and them, this client-side logic would place your result in the proper place in the page, without reloading the page. This is what isgenerally known as "ajax". It is not that complex, but the html + javascript side of the application become much more complex.
I think one should really understand the "Web 1.0" way before doing it the "Ajax way". in your case, let's suppose your HTML containing the calculator form is in a file called "calc.html". Inside it, where the result should lie, put a markup that can be understood by Python's built-in native string formatting methods, like {result} -
<html>
<body>
...
calculator body
...
Answer: <input type="text" readonly="true" value={result} />
</body>
</html>
And rewrite your code like:
import cgi
form = cgi.FieldStorage()
input1 = form.getvalue('input1')
input2 = form.getvalue('input2')
result = int(input1)+int(input2)
html = open("calc.html".read())
header = "Content-Type: text/html; charset=UTF-8\n\n"
output = header + html.format(result=result)
print (output)
The CGI way is outdated, but is nice for learning: it relies on your whole program being run, and whatever it prints to the standard output to be redirected to the HTTP request as a response. That includes the HTTP Headers, which are included, in a minimal form, above.
(I will leave the complete implementation of a way for the raw '{result}' string not to show up in the inital calculator form as an exercise from where you are 0- the path is to get the initial calculator html template through a CGI script as well, instead of statically, (maybe the same) as well - and just populate "result" with "0" or an empty string)
you can transfer response with the help of java script.
use under print("window.location=url")

How do I display a website with html-forms locally using python and collect the user input?

I am a behavorial scientist and usually collect data by letting participants do some tasks on a computer and record their responses (I write the programs using the pyglet wrapper PsychoPy). That is, the program runs locally and the data is stored locally.
Now I would like to know if there is a way to use Python to display a (local) website with html-forms to the user and collect the input (locally). The reason for this idea is that currently whenever I want to display checkboxes, radiobuttons, or input fields I use wxPython. This works quite well, but programming and layouting in wxPython is kind of cumbersome and I would prefer html with forms.
A requirement would be that it would need to rum without any borders, adress field, menu bar, ... The reason is that I need it in kind of fullscreen mode (I currently open a non-fullscreen pygflet window in the size of the screen to hide the desktop) so that participants can do nothing but work on the forms.
So I am looking for a way to (a) display html websites including html form above a pyglet window with no menu bar or whatsoever, (b) collect the input when clicking on the Ok button (i.e., the form is send), (c) control what is presented prior and after viewing this website, and (d) everything of this should happen locally!
My idea would be that the data is collected when participants hit the "Send away" button in the following example pic and the next page is displayed.
Update: I use windows (XP or 7).
This is a solution using Qt Webkit for rendering HTML. The default navigation request handler is wrapped by a function that checks for submitted form requests. The form uses the "get" method, so the data is included in the url of the request and can be retrieved that way. The original request is declined and you can change the content of the displayed web page as you wish.
from PyQt4 import QtGui, QtWebKit
app = QtGui.QApplication([])
view = QtWebKit.QWebView()
# intercept form submits
class MyWebPage(QtWebKit.QWebPage):
def acceptNavigationRequest(self, frame, req, nav_type):
if nav_type == QtWebKit.QWebPage.NavigationTypeFormSubmitted:
text = "<br/>\n".join(["%s: %s" % pair for pair in req.url().queryItems()])
view.setHtml(text)
return False
else:
return super(MyWebPage, self).acceptNavigationRequest(frame, req, nav_type)
view.setPage(MyWebPage())
# setup the html form
html = """
<form action="" method="get">
Like it?
<input type="radio" name="like" value="yes"/> Yes
<input type="radio" name="like" value="no" /> No
<br/><input type="text" name="text" value="Hello" />
<input type="submit" name="submit" value="Send"/>
</form>
"""
view.setHtml(html)
# run the application
view.show()
app.exec_()
As AdamKG mentioned, using a webframework would be a good choice. Since Django and similar might be an overkill here, using a micro webframework like 'flask' or 'bottle' would be a great choice.
This link demonstrates via step by step instruction how to make a simple form via a To-DO application. It assumes zero previous knowledge.
You can run it only locally also.
your want a simple solution, so just write a http server and run your simple page.
using python.BaseHTTPServer, coding a 15 line web server:
import BaseHTTPServer
class WebRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/foo':
self.send_response(200)
self.do_something()
else:
self.send_error(404)
def do_something(self):
print 'hello world'
server = BaseHTTPServer.HTTPServer(('',80), WebRequestHandler)
server.serve_forever()
easy enough,but i suggest using some web frameworks. They are easy too.
for example, web.py. here is what u want in 50 line codes:
install web.py
make a dir with 2 files:
./
|-- app.py
`-- templates
`-- index.html
index.html
$def with (form, ret)
<html>
<head>
<title> another site </title>
</head>
<body>
<h1> hello, this is a web.py page </h1>
<form action="" method="post">
$:form.render()
</form>
<h2>$:ret</h2>
</body>
</html>
app.py logic file:
import web
### Url mappings
urls = (
'/', 'Index', )
### Templates
render = web.template.render('templates')
class Index:
form = web.form.Form(
web.form.Textbox('fav_name', web.form.notnull, description="Favorite Name:"),
web.form.Textbox('cur_name', web.form.notnull, description="Current Name:"),
web.form.Button('Send Away'),
)
def GET(self):
""" Show page """
form = self.form()
return render.index(form, "")
def POST(self):
""" handle button clicked """
form = self.form()
if not form.validates():
return render.index(form, "INPUT ERROR")
# save data by ur method, or do some task
#pyglet.save_data(form.d.fav_name, form.d.cur_name)
#pyglet.draw(some_pic)
#os.system(some_cmd)
form = self.form()
return render.index(form, "YOUR DATA SAVED")
app = web.application(urls, globals())
if __name__ == '__main__':
app.run()
run this server in your windows:
python app.py 9999
open browser: http://127.0.0.1:9999/
by the way, if ur data is only strings, u can save them in web.by by sqlite.
My suggestion would be:
Use some python server as, for example SimpleHTTPServer. It is needed because the submit button on forms sends the information to a server. There you should manage the received info some way;
Have your browser configured with one of those Kiosk extensions, which disallow even the use of Alt+F4. An example would be Open Kiosk extension for Firefox
Optionally, if you have affinity with scripts in general, you could create a script which, when executed, would at the same time run the python server AND open your html file in the browser. That would ease a lot your setup work for every subject in your group.
EDIT: I've read you need the pyglet over the browser window. That could be included in the script of step 3, using "always on top" option and absolute positioning of the pyglet (I can tell this would probably be simpler on Linux, which could be run from persistent LiveUSB - just a thought!)
EDIT (regarding the posted comment):
I think the most reliable option for output would be to disk (file or database) instead or RAM (running python object), then you read the info from file afterwards. Then, in case of a surprise (system hang, power failure), the already-entered data would be there.
The only (and most important) part I don't know HOW to do is to handle the content of the form's "submit" on the server-side. Probably some server-side script file (php, python) shoud be created and left on the server root, so the server would receive an http request containing the info, and send the info to the script, which then handles the processing and file/database storage activities.
This might be of your interest:
"The POST request method is used when the client needs to send data to the server as part of the request, such as when uploading a file or submitting a completed form." (from wikipedia on "POST(HTTP)" ENTRY)
In another link, some thoughts on using SimpleHTTPServer itself for handling POST requests:
http://islascruz.org/html/index.php/blog/show/Python%3A-Simple-HTTP-Server-on-python..html
Hope this helps.
The reason for this idea is that currently whenever I want to display
checkboxes, radiobuttons, or input fields I use wxPython. This works
quite well, but programming and layouting in wxPython is kind of
cumbersome and I would prefer html with forms.
You can combine the ease of HTML and still create native Windows applications using Flex with a Python backend.
If you are averse to Flex, a bit more - involved - but still native windows application generator is Camelot
Edit
Instead of typing it out again - I would suggest the django + flex + pyamf article on Adobe that explains it all with screenshots as well. You can replace django with flask or bottle as they are more lightweight, however the PyAMF library provides native support for django which is why it was used in the example.
PyAMF provides Action Message Format (a binary protocol to exchange object with the flash runtime) support for Python.

How to loading/show a picture in a Python CGI page

I have written a little survey using Python and CGI. I am trying to show a picture using the normal <img> tag, But even-though the picture is in the same directory as my cgi script, my script cannot show it. I also changed the header to this:
print "Content-type: text/html; image/jpeg"
print
print """<html>
<head>
<title>You are going to be redirected</title>
</head>
<body bgcolor = #14b585>
<br>
<p align=center><font>Helloooo</font></p>
<img src="cat.jpeg" alt="cat" width="304" height="228"/>
<form action="./sample.py" method="post">
<p align=center><input type="submit" value="YES!" /></p>
</form>
</body>
</html>
"""
Why?(it is a very small jpg file)
print "Content-type: text/html; image/jpeg"
Don't change the header to that. You can't have multiple content types for a single document (multipart documents excluded, but browsers don't support them and that isn't the right format).
You are delivering an HTML document with an reference to an image in it. The image will be a separate request and response.
print "Content-type: text/html"
Or, better:
print "Content-type: text/html; charset=utf-8"
(Assuming you are using utf-8, which you should be).
print """<html>
Your Doctype is missing. This will trigger quirks mode, which is undesirable. You also have a great deal of legacy presentational markup that should be replaced by CSS.
<img src="cat.jpeg" alt="cat" width="304" height="228"/>
The context suggests that the image is decorative, so the alternative text should probably be "" (see Alt texts in IMGS), but there is nothing wrong with the actual reference to the image.
But even-though the picture is in the same directory as my cgi script
Since the HTML seems to be OK. You need to check that the image is.
Can you reach the image by typing the URL in directly?
What do the web server logs say when you try?
It is possible that your server is configured to try to treat everything in the directory as an executable, no matter what the file extension, so it might be trying to run the image as if it were a CGI program (which will obviously fail). If so, then you could either move the image or change the configuration of the server.
And I've just noticed this comment:
I did this in my browser: localhost/cgi-bin/cat.jpg and it got an error, I checked the logs, it Exec format error: exec of '/home/hossein/public_html/cgi-bin/cat.jpg' failed
That is what is happening. Moving the image is the simplest solution.
your apache was configured to use the cgi-bin directory as an CGI scripts folder, so any request that trying to get a file from this folder apache try to execute it as an CGI script. to make your image visible move it to the www/html folder.

Printing HTML in Python CGI

I've been teaching myself python and cgi scripting, and I know that your basic script looks like
#!/usr/local/bin/python
import cgi
print "Content-type: text/html"
print
print "<HTML>"
print "<BODY>"
print "HELLO WORLD!"
print "</BODY>"
print "</HTML>"
My question is, if I have a big HTML file I want to display in python (it had lines and lines of code and sone JS in it) do I have to manually add 'print' in front of each line and turn "s into \" , etc? Or is there a method or script that could convert it for me?
Thanks!
Python supports multiline strings, so you can print out your text in one big blurb.
print '''<html>
<head><title>My first Python CGI app</title></head>
<body>
<p>Hello, 'world'!</p>
</body>
</html>'''
They support all string operations, including methods (.upper(), .translate(), etc.) and formatting (%), as well as raw mode (r prefix) and the u unicode prefix.
If that big html file is called (for example) 'foo.html' and lives in the current directory for your CGI script, then all you need as your script's body is:
print "Content-type: text/html"
print
with open('foo.html') as f:
print f.read()
If you're stuck with Python 2.5, add from __future__ import with_statement as the start of your module's body. If you're stuck with an even older Python, change the last two lines into
print open('foo.html').read()
Note that you don't need to import cgi when you're using none of the functionality of the cgi module, which is the case both in your example and in this answer.
When I was first experimenting with decorators, I wrote this little CGI decorator to handle the HTML head and body tag boilerplate stuff. So that you can just write:
#CGImethod(title="Hello with Decorator")
def say_hello():
print '<h1>Hello from CGI-Land</h1>'
which when called returns:
Content-Type: text/html
<HTML>
<HEAD><TITLE>Hello with Decorator</TITLE></HEAD>
<BODY>
<h1>Hello from CGI-Land</h1>
</BODY></HTML>
Then say_hello could be called from your HTTP server's do_GET or do_POST methods.
Python supports multiline string. So you can just copy your HTML code and paste it into the quotations.
print ("<html>
<head>
<title>
</title>
</head>
</html>")
and so on!

Categories