Jak vyplnit webový formulář z Pythona
Teorie
Pokud znám políčka a strukturu předem, pouze vytvořím příslušnou HTTP hlavičku následovanou daty s odpověďmi (viz specifikace HTTP protokolu) a pošlu vše přes sokety na příslušnou IP adresu a port a rozeberu vrácenou HTTP odpověď pro případnou kontrolu chyb.
Pokud neznám políčka a strukturu předem musím před to zařadit krok parsování HTML/XHTML stránky - tj. extrakce značky <form>, jeho atributů action a method (případně encrypted) a všech polí <input>, <textarea>, <file> a já nevím co všechno tam může být.
Rozbor HTML
Mějme demonstrační stránku http://spreadsheets.google.com/viewform?key=piYHG7JxUHxstW-8oPftQHQ. Nejdříve si ji skuste vypnit ručně, a podívat se na výsledky http://spreadsheets.google.com/pub?key=piYHG7JxUHxstW-8oPftQHQ (zobrazí se po 5 minutách).
Nyní si rozebereme html kod z demonstrační stránky. Přeformátováno pro lepší čitelnost:
<body><h1>Anonymní dotazník</h1> <pre class="ss-form-desc"> tento dotazník pomůže lidem na celém světě ;-) </pre> <p> </p> <form action="http://spreadsheets.google.com/formResponse?key=piYHG7JxUHxstW-8oPftQHQ" method="POST"> <div class="ss-form-entry"> <span class="ss-q-title">Jméno </span> <span class="ss-q-help"> </span> <input type="text" class="ss-q-short" name="single:7" /> </div> <div class="ss-form-entry"> <span class="ss-q-title">Město </span> <span class="ss-q-help"> </span> <input type="text" class="ss-q-short" name="single:8" /> </div> <div class="ss-form-entry"> <span class="ss-q-title"># Jak se nazývá typ žloutenky - nemoc špinavých rukou? </span> <span class="ss-q-help">chřipka to není ;-) </span> <ul class="ss-choices"><li> <input type="radio" value=" žloutenka typu A" name="group:2" checked="checked" /> žloutenka typu A</li> <li> <input type="radio" value=" žloutenka typu B" name="group:2" /> žloutenka typu B</li> <li> <input type="radio" value=" žloutenka typu C" name="group:2" /> žloutenka typu C</li> </ul> </div> <div class="ss-form-entry"> <span class="ss-q-title">Jaké příznaky se nevyskytují u infarktu myokardu? </span> <span class="ss-q-help"> </span> <ul class="ss-choices"><li> <input type="checkbox" value="premenstruční syndrom" name="group:3" />premenstruční syndrom</li> <li> <input type="checkbox" value="zánět močového měchýře" name="group:3" />zánět močového měchýře</li> <li> <input type="checkbox" value="bolest na hrudi" name="group:3" />bolest na hrudi</li> </ul> </div> <div class="ss-form-entry"> <span class="ss-q-title">Napište něco o sobě </span> <span class="ss-q-help">jen tak ... </span> <textarea class="ss-q-long" name="single:5" rows="8" cols="75"></textarea> </div> <p> </p> <input type="submit" value="Odeslat" /> </form> <span class="ss-powered-by">používá technologii Dokumenty Google </span> <p> </p><small> <a href="http://www.google.com/accounts/TOS">Smluvní podmínky služby</a>- <a href="http://www.google.com/google-d-s/terms.html">Další smluvní podmínky</a></small> </body>
- na řádce 6 vidíme, jaká stránka se volá, když se formulář odesílá, ten použijeme i my. Tedy bude to http://spreadsheets.google.com/formResponse?key=piYHG7JxUHxstW-8oPftQHQ
- je tam 5 polí na vyplnění, každé se nějak jmenuje. Hledejte vždy parametr name= ... :
- Jméno = single:7
- Město = single:8
- Jak se nazývá typ žloutenky - nemoc špinavých rukou? = group:2 (je napsáno u jednotlivých položek)
- Jaké příznaky se nevyskytují u infarktu myokardu? = group:3
- Napište něco o sobě = single:5
Možná řešení
urlib
# -*- coding: utf-8 -*- import urllib, urllib2 adresa= "http://spreadsheets.google.com/formResponse?key=piYHG7JxUHxstW-8oPftQHQ" parametry= { "single:7": "Bystroushaak", "single:8": "Litomerice", "group:2": "Žloutenka typu B", "group:3": "Zánět močového měchýře", "single:5": "Tento formular byl vyplnen scriptem od Bystroushaaka!"} params= urllib.urlencode(parametry) # Prekoduje parametry do tvaru vhodneho pro odeslani req= urllib2.Request(adresa, params) # Vytvori request, coz je smichanina adresy a parametru, pripadne i hlavicek spojeni = urllib2.urlopen(req) # Otevre spojeni.read() # a nacte stranku spojeni.close()
Program je jistě možno doplnit o načítání jednotlivých parametrů přes raw_input() nebo pomocí jakéhokoliv GUI, ale to si jistě laskavý čtenář udělá sám nebo se zeptá v konferenci.
zope.testbrowser
Stáhněte a nainstalujte modul z http://pypi.python.org/pypi/zope.testbrowser - úplně dole je soubor ke stažení. Kod programu:
# -*- coding: utf-8 -*- from zope.testbrowser.browser import Browser browser = Browser('http://spreadsheets.google.com/viewform?key=piYHG7JxUHxstW-8oPftQHQ') form = browser.getForm() # ukázka získání možných voleb c = form.getControl(name='group:2') print c.options # vyplnění některých polí c.getControl(value=' žloutenka typu C').selected = True form.getControl(name='single:7').value = 'Honza Nový' form.getControl(name='single:8').value = 'Nová Ves' form.getControl(name='group:3').value = ['premenstruční syndrom', 'zánět močového měchýře'] form.getControl(name='single:5').value = 'pěkný příklad' form.submit() print browser.contents
Možné trable
Je možné, že časem narazíte na problém se souborem robots.txt. Poznáte to tak, že vám nepůjde načíst stránka a jako chybu bude Python hlásit toto:
Traceback (most recent call last): File "<stdin>", line 3, in <module> File "c:\python25\lib\site-packages\zope.testbrowser-3.4.2-py2.5.egg\zope\test browser\browser.py", line 224, in open self.mech_browser.open(url, data) File "build\bdist.win32\egg\mechanize\_mechanize.py", line 203, in open File "build\bdist.win32\egg\mechanize\_mechanize.py", line 254, in _mech_open mechanize._response.httperror_seek_wrapper: HTTP Error 403: request disallowed by robots.txt
Existují dva způsoby jak to vyřešit:
- dočasná úprava konfigurace objektu Browser:
>>> >>> from zope.testbrowser.browser import Browser >>> >>> browser= Browser() >>> >>> browser.mech_browser.set_handle_robots(False)
- trvalá úprava:
- otevřete si soubor Python25\Lib\site-packages\zope.testbrowser-3.4.2-py2.5.egg\zope\testbrowser\browser.py
- přidejte 160 řádek v tomto tvaru: self.mech_browser.set_handle_robots(False)
- výsledek by měl vypadat nějak takto: http://img84.imageshack.us/my.php?image=broyu3.jpg