Seite 1 von 1
Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 08:47
von mzh
Hallo Leute
In diesem Post geht es um folgendes: Auf einer HTML Seite ist ein Knopf, wenn dieser geklickt wird, so soll ein Pythonskript ausgeführt werden ('script.cgi'). Das Skript soll ein 'text' Feld auslesen-- um zu überprüfen ob das auch funktioniert wollte ich den Text der eingegeben wird in ein File schreiben, muss aber nicht sein.
Ein paar Dinge verstehe ich nicht ganz:
- Braucht man hier JavaScript?
Jetzt sieht es ungefähr so aus:
HTML:
Code: Alles auswählen
<FORM onSubmit="return OnSubmitForm();"
METHOD="POST"
ENCTYPE="multipart/form-data"
name="connectForm"
<input type="submit" value="CONNECT" name="connect"
onClick="document.pressed=this.name"> </p>
Text Input: <input type="text" name="textInput">
</form>
Also, der Knopf ist in der Form und das Textfeld auch. Damit der Server das CGI Skript startet, hab ich hier ein JavaScript:
Code: Alles auswählen
function OnSubmitForm() {
document.connectForm.action ="hello.cgi"
return true;
}
Wenn ich das jetzt richtig verstehe (den Code hab ich von einem Kollegen bekommen der aber im Moment weg ist), dann läuft das so, dass der onSubmit-Variable (im form-tag) 'true' zugewiesen wird und gleichzeitig wird festgelegt, welches CGI-Skript ausgeführt werden soll (nämlich hello.cgi). Dh. der Browser bewirkt, dass hello.cgi ausgeführt wird.
Ich verstehe aber leider nicht, wie das der Teil im Input-tag bedeutet. V.a. krieg ich nicht rein, was 'onClick' zugewiesen wird, also 'document.pressed=this.name'.
Der letzte Teil wäre nun das CGI Skript.
Damit habe ich ja Zugriff auf die Elemente der Form.
Code: Alles auswählen
#!/usr/bin/python
import cgi
import cgitb
cgitb.enable()
form = cgi.FieldStorage()
print "Content-type: text/html\n\n"
print
print form['textInput'].value
Das sollte ja doch den Text ausgeben, der in das Textfeld geschrieben wurde.
Vielen Dank, wenn jemand etwas Licht ins Dunkel bringen könnte.
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 09:05
von snafu
Muss es wirklich Python-Code sein, der sozusagen aus einer HTML/JavaScript-Umgebung aufgerufen wird? Der übliche Weg ist eigentlich, dass man mittels Web-Framework eine App baut, dort die "Ereignisse" (Seite anfordern mittels GET, Daten senden mittels POST) abfängt und entsprechenden HTML-Code zurückgibt. Als Empfehlung seien wie immer Bottle oder Flask genannt. Infos zu beiden findest du über eine Suchmaschine.
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 09:14
von mzh
Die Idee hinter dem Ganzen ist, dass ich jetzt etwas mit Python geschrieben habe, das über das Internet ausführbar sein soll, deshalb wäre ich froh, wenn das so möglich wäre.
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 09:18
von BlackJack
@mzh: Einfach nur um Form-Daten an ein CGI-Skript zu schicken benötigt man kein JavaScript.
Dem `onsubmit`-Attribut wird nicht ``true`` zugewiesen, sondern das Stückchen JavaScript-Code als Zeichenkette. Der wird ausgeführt, wenn die Formulardaten abgeschickt werden sollen, beziehungsweise kurz vorher. Der Code sorgt dann dafür, dass das Attribut `action` von dem Form auf "hello.cgi" gesetzt wird. Warum die Funktion ``true`` zurück gibt und warum für den Aufruf ein ``return`` mit in dem Code bei `onsubmit` steht, ist mir nicht klar. Ist IMHO beides überflüssig.
Der `onclick`-Code hat auch nichts mit dem eigentlichen Problem zu tun -- ist also hier auch überflüssig.
Wo liegt denn jetzt das Problem? Hier müssen ja viele Komponenten zusammen spielen. Das HTML, der Browser (JavaScript), der Server. Wenn es nicht das tut was es soll, musst Du erst einmal heraus finden an welcher Stelle dieser Kette es hängt. Werden die Form-Daten abgeschickt? Ist der Server so konfiguriert, dass er das CGI-Skript ausführt? Kommen die Daten dort an?
Ein allgemeiner Text über CGI, wie die entsprechenden Abschnitte bei
SelfHTML wären vielleicht an dieser Stelle auch eine nützliche Lektüre.
Und natürlich wie immer die Frage bei CGI -- muss es denn wirklich CGI sein? Wie schon gesagt wurde Bottle und Flask existieren.
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 09:25
von /me
mzh hat geschrieben:
Jetzt sieht es ungefähr so aus:
HTML:
Code: Alles auswählen
<FORM onSubmit="return OnSubmitForm();"
METHOD="POST"
ENCTYPE="multipart/form-data"
name="connectForm"
<input type="submit" value="CONNECT" name="connect"
onClick="document.pressed=this.name"> </p>
Text Input: <input type="text" name="textInput">
</form>
Das "ungefähr" stimmt mich etwas stutzig. Vielleicht ist das Original ja in Ordnung, aber das da oben ist ein ziemlich kaputtes HTML-Fragment.
Wenn JavaScript nicht für andere Dinge hier zwangsweise erforderlich ist, dann würde ich völlig darauf verzichten.
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 09:46
von mzh
@ me: gemeint ist, die HTML Tags html, head, title, body wurden weggelassen, sorry kann man ja nicht wissen.
@ BlackJack: Danke für die Hinweise. Die JavaScript Funktion würdest du also eher so schreiben:
Code: Alles auswählen
function OnSubmitForm() {
document.connectForm.action ="hello.cgi"
}
und das Form-Tag: <FORM onSubmit="OnSubmitForm();" METHOD="POST" ENCTYPE="...">, also ohne 'return'.
Ok, also dem 'action'-Attribut der Form wird das 'hello.cgi' Skript zugewiesen. Wenn ich das richtig verstehe, dann erweitert das JavaScript also die Attributliste der Form? Im Form-Tag steht ja kein 'action'-Attribut.
Das soll keine grosse Sache werden, im Prinzip ist es ziemlich simpel, der kompliziertere Teil wird auf der Serverseite erledigt. Alles was möglich sein soll ist das der Benutzer ein oder zwei Parameter mitgeben kann und dann soll das laufen.
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 10:09
von BlackJack
@mzh: Auch mit den genannten Tags ist das noch kaputt. Das Start-Tag vom ``form`` wird zum Beispiel nicht geschlossen, was dazu führt dass gar keine Schaltfläche zum Abschicken der Daten angezeigt wird.
Ich würde die überflüssigen ``return``\s weglassen, ja. Aber vielleicht auch gleich das überflüssige JavaScript ganz. Wo liegt der nutzen das `action`-Attribut per JavaScript zu setzen, wenn man es auch gleich ins HTML schreiben kann!?
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 10:14
von Hyperion
mzh hat geschrieben:
Ok, also dem 'action'-Attribut der Form wird das 'hello.cgi' Skript zugewiesen. Wenn ich das richtig verstehe, dann erweitert das JavaScript also die Attributliste der Form? Im Form-Tag steht ja kein 'action'-Attribut.
Dann schreib da doch mal eins rein!!!
mzh hat geschrieben:
Das soll keine grosse Sache werden, im Prinzip ist es ziemlich simpel, der kompliziertere Teil wird auf der Serverseite erledigt. Alles was möglich sein soll ist das der Benutzer ein oder zwei Parameter mitgeben kann und dann soll das laufen.
Wie bereits empfohlen nutze dafür dennoch ein Framework! Django ist (fast) immer die richtige Wahl; willst Du nur dieses bisschen machen und Dich nie wieder mit Webprogrammierung befassen, dann würde ich Dir flask empfehlen.
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 10:31
von mzh
Da ging eine Klammer beim Kopieren verloren.
Gut, ich versuchs ohne JavaScript.
Aber wie merkt dann der Server, das der Submit-Button geklickt wird?
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 10:54
von BlackJack
@mzh: Der Server bemerkt das gar nicht -- der Browser tut das. Und der ruft dann die unter `action` hinterlegte URL auf und schickt dort den Form-Inhalt hin. Lies doch mal SelfHTML oder irgend eine andere Quelle zum Thema CGI.
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 12:54
von mzh
Also, ich hab jetzt ein Minimalbeispiel am laufen.
Hier der HTML Teil:
Code: Alles auswählen
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/htm
l4/loose.dtd"-->
<html>
<head>
<title>Title: HELLO</title>
<link rel="stylesheet" href="../a_presentation/baker.css" type="text/css">
</head>
<body>
<h2>Body: HELLO-- a_content/hello.html</h2>
<FORM METHOD="POST" name="helloForm" action="./hello.cgi">
<p>Text Input: <input type="text" name="nameInput"></p>
<p>Submit: <input type="submit" value="Submit"></p>
</form>
</body>
</html>
Das CGI-Skript, mit dem ich dann den Form-Werte auslesen, in Parameter speichern und an die weiteren Pythonskripte senden will, sieht so aus (und befindet sich im selben Verzeichnis):
Code: Alles auswählen
#!/usr/bin/python
print "Content-type: text/html\n\n"
import cgi
import cgitb
#cgi.test()
cgitb.enable()
page = '<html>\
<head>\
<title>\
Title: hello.cgi\
</title>\
</head>\
<body>\
Body: hello.cgi\
</body>\
</html>'
print page
Ich konnte auch den Wert, den ich ins Textfeld eingegeben habe, anschliessend über die Form auslesen und im CGI Skript wieder (mit String-Formatting) wiedergeben.
Das Ganze scheint jetzt etwas robuster geworden zu sein.
Eine Frage: woran kann es liegen, dass ich im CGI-Skript bspw. ohne weiters urllib importieren kann, allerdings ist es nicht möglich ein selbstgeschriebenes Modul zu importieren. Wenn ich allerdings den Pythoninterpreter starte, dann lässt sich besagtes Modul ohne weiters (von jedem Verzeichnis aus) importieren.
Was kann da die Ursache für dieses Verhalten sein?
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 16:37
von BlackJack
@mzh: Wie versuchst Du denn das Modul zu importieren? Und wo liegt das? Hat der Benutzer unter dem der Webserver läuft entsprechende Zugriffsrechte?
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 22:10
von mzh
Ich verstehe nicht ganz wie du 'wie' meinst?
Im CGI-Skript steht 'import connect' (das Modul das ich importieren will heisst 'connect').
Im Apache2 error.log file steht dann: ImportError: No module named connect.
Wenn ich den Pythoninterpreter aus genau dem Verzeichnis starte, in dem das CGI-Skript liegt, so kann ich ohne Probleme 'import connect' ausführen.
Wäre echt froh, wenn ich das irgendwie hinkriege. Ansonsten, was gäbe es dann sonst noch, das 'connect' Modul auszuführen? 'connect' ist jetzt ein Python-File, sonst müsste ich ja daraus auch ein CGI-File machen. Wäre das eine Möglichkeit?
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 22:15
von deets
Nein. Das hat damit nichts zu tun. Fuer dein Problem gibt es eine sehr grosse Menge an Loesungen. Das Grundproblem besteht darin, dass du dein Modul "connect" im Interpreter deshalb findest, weil die Liste der Pfade, die Python absucht, automatisch den aktuellen Pfad beinhaltet.
Versuch mal zB in das draueberliegende Verzeichnis zu wechseln, und dann "Python pfad/mein.cgi" aufzurufen. Dann ist essig mit connect importieren.
Um das Problem zu loesen gibt es eine ganze Reihe von Moeglichkeiten. Da du ja beharrlich alle Hinweise darauf, dass ganze mit einem Webframework zu machen ignorierst, hier mal die einfachste fuer deinen Fall: vor dem import musst du sys.path so abaendern, dass der import klappt.
Also so etwa:
Code: Alles auswählen
import sys
import os
sys.path.append(os.dirname(__file__)) # den Pfad zum aktuellen Skript einhaengen
import connect # sollte jetzt gehen.
Falls das doch Probleme macht, weil aus irgendwelchen Gruenden __file__ nicht gesetzt ist, kannst du natuerlich auch den Pfad zum beinhaltenden Verzeichnis hart kodieren.
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 23:06
von mzh
@deets:
es ist nicht so, dass ich hier grundsätzlich mich gegen ein Framework sträuben will. Es ist nur so, dass ich einfach eine irgendwie laufende Version am laufen haben will, damit ich sehen kann ob das Program in der Art und Weise wie ich es mir vorstelle auch irgendwie funktioniert. Ich hab mir das Flask-Framework angeschaut, ich hab aber im Moment schlicht keine Zeit mich damit auseinanderzusetzen..
Ich hab deinen Code versucht (in Python3 und Python2.4), leider funktioniert es nicht. Bist du sicher dass os.dirname stimmt?
Code: Alles auswählen
mzh $ python2.4
Python 2.4.3 (#2, Jan 21 2010, 19:56:43)
[GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.dirname
Traceback (most recent call last):
File "<stdin>", line 1, in ?
AttributeError: 'module' object has no attribute 'dirname'
>>>
Sowie
Code: Alles auswählen
mzh $ python
Python 3.1.1 (r311:74480, Nov 16 2010, 14:33:59)
[GCC 4.0.3 (Ubuntu 4.0.3-1ubuntu5)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> os.dirname
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'dirname'
>>>
Re: Von HTML Knopf in Python rein
Verfasst: Mittwoch 27. April 2011, 23:15
von BlackJack
@mzh: Falls mit "das" `os.dirname()` gemeint sein sollte: Das heisst eigentlich `os.path.dirname()`.
Re: Von HTML Knopf in Python rein
Verfasst: Donnerstag 28. April 2011, 09:01
von mzh
@BlackJack, cool.
@deets: ach so, in der interaktiven Session ist das __file__ Attribute nicht definiert. Klar, dass meine Beispiele nicht laufen.
Ich habs jetzt so hingekriegt:
Code: Alles auswählen
import os.path
print(os.path.dirname(os.path.abspath(__file__)))
Ich möchte meine Ursprüngliche Frage nochmals anders stellen:
Ganz konkret geht es darum, dass folgendes Skript über einen Knopf auf einer Webseite gestartet werden kann. Das Skript ruft ein paar Programme auf, die auf dem Server installiert sind und schreibt ein paar Files, mehr nicht.
Alles was ich möchte ist jetzt, dass der Besucher der Website dieses Skript starten kann.
Code: Alles auswählen
#!/usr/local/bin/python3
"""Description of the 'connect' module.
The 'connect' module prepares the BioFET-SIM calculation.
It carries out the following steps:
- Download of the PDB file
- Fixing the PDB file with PDB2PQR
- Realigning the protein structure with VMD
- From the realignment, the dimensions are obtained
- Calculation of overall charge with PROPKA 3.
"""
# NOTE:
# - Calls all functions in order to obtain the
# charge, charge-carrier number and dimensions
# of the protein.
# Default modules
import sys
import os
import time
from os.path import splitext
from subprocess import call
# Custom modules
import propka
import getCharge
import getDimension
# Builtin modules
#import realign
#import getPointCharges
#import getCharge
from signature import signature
from tests import hasExt
from parse import parse
# ************************************************************
# ************************************************************
# SETUP
def setup(pdbfile):
"""Setting up the run.
The function handles the submitted argument, ie. it checks
if there is an extension or not. Incase it is missing, it is
appended, incase it is present, the extension remains.
setup(<PDB_ID[.pdb]>) --> target
The return value is an uppercase string including the '.pdb'
extension.
"""
signature('SETUP')
# Handle the case with/without extension in the argument
if hasExt(pdbfile):
target = pdbfile.upper()
else:
target = pdbfile.upper() + '.pdb'
return target
def getPDB(target):
"""Obtain the PDB file.
The 'target' argument is the correct file name, including
the '.pdb' extension, eg. '1AVD.pdb'.
The file is written to disc after download."""
print("Provided PDB file: " + target)
print("Requesting PDB file: " + target)
#call(['wget', 'http://www.pdb.org/pdb/files/'\
# + target])
os.system("wget http://www.pdb.org/pdb/files/"\
+ target)
# ------------------------------------------------------------
# ************************************************************
# ************************************************************
# PDB2PQR Part
def callPDB2PQR(target):
signature('PDB2PQR')
call(['pdb2pqr.py', '-v', '--ff=CHARMM', target,\
splitext(target)[0] + '-out.pqr'])
#os.system('pdb2pqr.py -v --ff=CHARMM ' + target\
# + ' ' + splitext(target)[0] + '-out.pqr')
print('PDB2PQR done.')
print()
# ------------------------------------------------------------
# ************************************************************
# ************************************************************
# VMD Part
def callVMD(target):
signature('VMD')
#call(['align.py', target])
os.system('realign.py ' + target[0:4] + '-out.pqr')
print('VMD done.')
print()
# ------------------------------------------------------------
# ************************************************************
# ************************************************************
# PROPKA Part
def callPropka3(target):
signature('PROPKA')
#call(['cp', splitext(target)[0] + '-out.pqr',\
# splitext(target)[0] + '-out.pdb'])
#call(['propka.py', splitext(target)[0] + '-out.pdb'])
#os.system('cp ' + splitext(target)[0] + '-out.pqr'\
# ' ' + splitext(target)[0] + '-out.pdb')
if os.system('propka.py ' + splitext(target)[0] +\
'-out-new.pdb') == 0:
print('Propka 3 done.')
print()
# ------------------------------------------------------------
# ************************************************************
# ************************************************************
# BOX Part
def callBox(target):
signature('BOX')
dim = getDimension.BoxPDB(target)
print(dim.boxIt())
# ------------------------------------------------------------
# ************************************************************
# ************************************************************
# COLLECT Part
def collectData(pH, target):
signature("COLLECTING DATA")
charge = getCharge.getCharge(pH, target)
print('Charge at pH {0}: {1}'.format(pH, charge[1]))
print()
# ------------------------------------------------------------
# ************************************************************
# ************************************************************
# Entry point of Python.
try:
# Get the argument
pdbfile = sys.argv[1]
target = setup(pdbfile)
# Download
getPDB(target)
# OUT: 'PDB.pdb'
# Correction
# IN: 'PDB.pdb'
callPDB2PQR(target)
# OUT: 'PDB-out.pqr'
# Realignment
# IN: 'PDB-out.pqr'
callVMD(target)
# OUT: 'PDB-out-new.pdb'
# Charging
# IN: 'PDB-out-new.pdb'
callPropka3(target)
# OUT: 'PDB-out-new.pka'
if 1:
# pH=7
parse(target)
collectData(7, target)
else:
for i in range(1,15):
collectData(i, target)
print(callBox(target))
except IndexError:
if len(sys.argv) == 1:
print("No argument provided.")
print("$ connect.py <PDB>")
# End of the program.
# ************************************************************
# ************************************************************
Aus irgendeinem Grund wird der wget Befehl ausgeschrieben.. das sieht im Code normal aus.
Wie kann ich das machen? Wenn ein Framework (Flask) die beste Lösung ist, dann probiere ich es aus. Ich habe einfach etwas die Befürchtung, dass es dann nur noch etwas komplizierter wird.. deshalb habe ich bis anhin versucht es zu vermeiden. Ich bin mir auch bewusst, dass das Skript so wahrscheinlich alle Programmierpraktiken ausdolcht, Hinweise in dieser Richtung nehme ich gerne entgegen, allerdings haben diese für mich im Moment weniger Priorität.
Danke für weiteren Input.