Seezeit Mensa: Speisepläne per Python abrufen

Bevor ich diese Liste mit URLs für den einfachen Abruf des Speiseplans in Form von XML-Dokumenten gefunden hatte (was sicherlich die elegantere Lösung ist – so sind dort auch die Preise enthalten, was auf der Webseite nicht der Fall ist), hab ich ewig versucht die Daten per einfachem POST-Request abzurufen: Denn auf der Seezeit Speiseplan-Webseite werden die Daten ganz einfach per AJAX abgerufen… „Das kann doch nicht so schwer sein“, hab ich mir gedacht… Übrigens: Dieser Beitrag dürfte auch für eine ganze Reihe anderer Mensen gelten, da das Studentenwerk Seezeit hierbei auf einen externen Dienstleister zurückgreift: Die infomax GmbH – und die entsprechende URL, auf der die Speisepläne gehostet werden lautet http://www.max-manager.de

Nur irgendwie war das dann doch nicht so einfach wie ich gedacht hatte: Alle POST-Anfragen wurden zwar mit einem „200“er-Statuscode beantwortet, der eigentlich besagt, dass alles in Ordnung sei. Leider war das NICHT der Fall: Der Response-Body war leer – 0 Byte groß… Nach langem Rätseln kam ich dann auf die Lösung: Mein kleines Python-Skript hatte die POST-Parameter in einer anderen Reihenfolge zu gesendet, als es der Browser auf der Webseite machte. Und der Server war dann der Meinung, bis auf den Header einfach mal gar nichts zurückgeben zu müssen. Dafür, dass er bei der Reihenfolge der POST-Parameter so wählerisch war, scheinen ihm die Header aber ziemlich egal sein (das war meine erste Vermutung, dass da was nicht stimmt). Deswegen habe ich diese dann auch nicht weiter spezifiziert, sondern einfach das Requests-Modul entscheiden lassen, was es an Standard-Headern es mitsenden möchte.

Im Folgenden möchte ich daher festhalten, wie man ganz einfach per POST-Request an die Essensdaten kommt (sprich: Insbesondere, wie ich die POST-Parameter in die korrekte Reihenfolge bringe). Benutzt habe ich das Python-Modul „Requests„, das sich selber mit „HTTP for Humans“ betitelt. Wer sich mal einen einfachen POST-Request mit den mitgelieferten Python-Werkzeugen urllib / urllib2 angeschaut hat, weiß was gemeint ist 😉 Daher kann ich hier die Verwendung nur empfehlen.

import requests
url = 'http://www.max-manager.de/daten-extern/seezeit/html/inc/ajax-php_konnektor.inc.php'
values = [('func' , "make_spl"),
          ('loc' , 'mensa_giessberg'),
          ('lang' , 'de'),
          ('date'  , '2014-02-21')]

r = requests.post(url, data=values)
print r.text

Der Clou dabei ist, dass entgegen der meisten Beispiele in der Dokumentation nicht ein Dictionary mit den Parametern übergeben wird, sondern eine Liste. Die Liste garantiert dabei, dass die Einträge nicht „beliebig“ durcheinandergewürfelt werden, sondern genau ist der definierten Reihenfolge behalten werden.

Für loc kann man einen der folgenden Werte einsetzen (vermutlich gehen auch noch andere Werte, aber ich beziehe mich hier nur auf die Mensen der Seezeit):

  • mensa_giessberg (Mensa der Uni Konstanz)
  • themenpark_abendessen (Abendessen an der Uni Konstanz)
  • mensa_htwg (Mensa der HTWG Konstanz)
  • mensa_friedrichshafen (Mensa der Dualen Hochschule BW Fallenbrunnen/Friedrichshafen)
  • mensa_weingarten (Mensa der HS/PH Weingarten)
  • mensa_ravensburg (Mensa der Dualen Hochschule BW Ravensburg)

Für lang ist außer einem de noch ein en möglich, wodurch dann die englischen Namen der Speisen zurückgegeben werden.

Das Feld date ist wohl selbsterklärend 😉

Vom Server wird eine einfache HTML-Tabelle zurückgeliefert. Diese könnte man nun parsen, per CSS aufhübschen, oder was auch immer damit machen 😉

Dem obigen Code fehlt (aus Gründen der Übersichtlichkeit) natürlich noch das entsprechende Error-Handling. Nachdem ich das hinzugefügt hatte, sieht mein Code jetzt folgendermaßen aus:

import requests, sys
from requests.exceptions import *
url = 'http://www.max-manager.de/daten-extern/seezeit/html/inc/ajax-php_konnektor.inc.php'
values = [('func' , "make_spl"),
          ('loc' , 'mensa_giessberg'),
          ('lang' , 'de'),
          ('date'  , '2014-02-21')]

try:
    # Try to request the data
    r = requests.post(url, data=values)
except ConnectionError:
    print("Could not reach server. Make sure your internet connection is working." )
    sys.exit(1)
except HTTPError:
    print("The Server responsed with an Error.")
    sys.exit(1)
except Timeout:
    print("Timeout occured when tried to fetch data from server.")
    sys.exit(1)
except:
    print("An unknown error occured fetching the data from server.")
    sys.exit(1)
else:
    if r.status_code != 200:
        print("Error: Server returned status code '" + str(r.status_code) + "'.")
        sys.exit(1)

# As we can be pretty sure now that there was no error, we can print the response
print(r.text)
Advertisements
Dieser Beitrag wurde unter Python veröffentlicht. Setze ein Lesezeichen auf den Permalink.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s