Open Source im professionellen Einsatz
Linux-Magazin 06/2017
© maksym yemelyanov, 123RF

© maksym yemelyanov, 123RF

Multilingualer Programmier-Snapshot zum Einholen von Webseiten

Turm von Babylon

Schnell ein Skript geschrieben – und schon steht der Programmierer vor dem typischen Problem: Wie ein HTTP-Dokument vom Web holen, welche Sprache macht es am einfachsten?

830

Kaum eine Programmieraufgabe zeigt die Unterschiede zwischen den gängigen Sprachen so deutlich wie das Einholen eines Dokuments vom Web. Admins greifen bei Shellskripten oft auf das Utility »curl« zurück, das die Daten hinter einer URL ohne viel Federlesen überträgt und auf der Standardausgabe ausgibt.

Doch was ist, wenn die URL ins Nirwana zeigt? Der Server den Zugriff verweigert? Was passiert, falls der Server einen Redirect zurückgibt? So liefert »curl http://google.com« nicht die erwartete HTML-Seite mit dem Suchformular, sondern nur einen Hinweis, dass die gewünschte Seite wohl auf »www.google.com« zu finden ist. Mit der Option »-L« folgt »curl« hingegen dem Verweis und pumpt dann im Anschluss die Daten aus der dort gefundenen Quelle.

Oder was passiert bei einer Riesendatei wie einem 4K-Film? Geht dem Prozess der RAM-Speicher aus, weil er alles auf einen Rutsch runterschlingt? Klappt bei einer HTTPS-URL die Verschlüsselung mit dem SSL-Protokoll automatisch, und prüft das Utility das Zertifikat des Servers ordnungsgemäß, damit sie nicht auf einen Man-in-the-Middle-Angriff hereinfällt? Wie das gute alte »curl« bieten populäre Programmiersprachen all dies, wenngleich auch oft nur als Zusatzpaket und oft mit eigenwilligem Ansatz.

Go, Hipster go!

Dem relativ neuen Go liegt der Websupport schon von Haus aus mit dem Paket »net/http« bei, mustergültig inklusive SSL-Support. Go-Programmierer behandeln eventuell auftretende Fehler sofort nach Funktionsaufrufen und können sich nicht darauf hinausreden, dass geworfene Exceptions schon irgendwo abgehandelt werden – und wenn es erst als schwer leserlicher Stack-Trace beim Abbruch des Programms ist. Zweifellos eine Philosophie-Frage mit ähnlicher Tragweite wie die Entscheidung für einen Ehepartner oder für einen der Editoren »vi« oder »emacs« .

Listing 1 zeigt gleich drei verschiedene Fehlerprüfungen, denn sowohl die Erzeugung des Requests kann schiefgehen (nicht unterstütztes Protokoll), der Server kann einen Fehlerstatus-Code liefern (404 bei nicht gefundenem Dokument) und schließlich kann beim Einholen der Daten über verschlungene Pfade des Internets ein Fehler auftreten, der zum Abbruch des Datenstroms führt. In Go geben Funktionen daher gern zwei Parameter zurück, ein Ergebnis und eine Fehlerstruktur, deren Wert auf »nil« gesetzt ist, falls alles glattgegangen ist.

Listing 1

http-get.go

01 package main
02 import "fmt"
03 import "net/http"
04 import "io/ioutil"
05
06 func main() {
07     resp, err := http.Get("http://google.com")
08
09     if err != nil {
10         fmt.Printf("%s\n", err)
11         return
12     }
13
14     if resp.StatusCode != 200 {
15         fmt.Printf("Status: %d\n",resp.StatusCode)
16         return
17     }
18
19     defer resp.Body.Close()
20     body, err := ioutil.ReadAll(resp.Body)
21     if err != nil {
22         fmt.Printf("I/O Error: %s\n", err)
23         return
24     }
25
26     fmt.Printf("%s\n", body)
27 }

Interessant ist auch, dass das Paket »net/http« zuerst den Request ausführt, in Zeile 14 dann den Statuscode des Servers empfangen hat, sich aber mit dem Abpumpen der Body-Daten noch Zeit lässt. Die schaufelt »ReadAll()« aus dem Paket »io/ioutil« erst später weg, und die »Close()« -Methode auf das Body-Objekt zeigt abschließend an, dass die Request-Abarbeitung tatsächlich beendet ist und Go die Daten entsorgen kann. Das zugehörige Kommando steht schon in Zeile 19, wird aber mit dem eleganten Schlüsselwort »defer« bis zum Ende der gerade ausgeführten Funktion verzögert.

Schlankes Python

Anders dagegen die Python-3-Implementierung in Listing 2 mit der modernen Bibliothek »requests« : Sie ist kompakter, weil Python Exceptions wirft, die Entwickler zentral prüfen können. Ob der Request ein nicht existierendes Protokoll spezifiziert (»abc://« ), die Serverzertifikats-Prüfung bei SSL fehlschlägt oder ein I/O-Fehler auftritt, alles löst eine entsprechende Exception aus, die der Code entweder gesondert oder wie in Zeile 11 in einem Aufwasch prüft.

Listing 2

http-get.py

01 #!/usr/bin/python3
02 import requests
03
04 try:
05     r = requests.get("http://google.de");
06     if r.status_code == 200:
07         r.encoding = 'utf-8'
08         print(r.text)
09     else:
10         print(r.status_code)
11 except Exception as exp:
12     print("Error: " + str(exp))

Das ist sicher bequemer, doch die eingesparte Tipparbeit kann sich später rächen, wenn eine Exception aus den Untiefen des Codes hochgespült wird und keiner mehr weiß, woher sie eigentlich kommt. Auch die Lesbarkeit des Codes leidet, denn es ist nicht ganz klar, welche Zeile im »try« -Block die Exception ausgelöst hat. Das Thema hat schon zahllose schwer schlichtbare Endlosdiskussionen angezettelt.

Lustig ist auch, dass »r.encoding« nach einem Request auf »google.de« angibt, dass die Seite in ISO-8859-1 erscheint. Erst manuelles Umschwenken auf »utf-8« in Zeile 7 veranlasst das folgende »r.text« , den Inhalt UTF-8-kodiert auszugeben. Ein Statuscode ungleich 200 wirft von Haus aus keine Exception und will manuell geprüft sein. Wer es noch kompakter mag, kann mit der Methode »raise_for_status()« eine Exception werfen, falls der Server etwas anderes als 200 gemeldet hat.

Diesen Artikel als PDF kaufen

Express-Kauf als PDF

Umfang: 3 Heftseiten

Preis € 0,99
(inkl. 19% MwSt.)

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Perl-Snapshot

    Der Musikstreaming-Service Spotify pumpt gegen eine monatliche Gebühr Musik auf den Desktop und aufs Smartphone. Noch mehr Groove hat, dass Perl-Hacker Michael Schilli per Oauth-geschütztem Web-API seine Spotify-Playlisten für die Ewigkeit archiviert.

  • Perl-Snapshot

    Ist Perlmeister Schilli unterwegs, weiß er gern, was daheim abgeht. Mit zwei Skripten bekommt er es hin, dass die angeschaffte Billigkamera über das Tumblr-API zyklisch Schnappschüsse auf der Micro-Blogplattform ablegt. Tierisch schick, diese Überwachung.

  • Perl-Snapshot

    Ein Screenscraper und eine Applikation für das offizielle Ebay-API lösen Alarm bei neu eingegangenem Kunden-Feedback aus und spüren Fehler in der monatlichen Ebay-Abrechnung auf.

  • Perl-Snapshot

    Mit einer chinesischen Guillotine und einem Einzugsscanner bewaffnet geht Perlmeister Michael Schilli diesmal seinen Büchern an den Leim. Die Grundlage seiner bibliophoben Tat liefert Google Drive, das mit 5 GByte genug Speicherplatz für ein Online-PDF-Lager mit eingescannten Büchern bietet.

  • IRC-Bots

    Warum sollten Chaträume nur für Menschen da sein? Dominik Honnef zeigt, wie sich spezialisierte Bots in Wissensdatenbanken oder Ticketsysteme einbinden lassen und so die Arbeit erleichtern.

comments powered by Disqus

Ausgabe 06/2017

Digitale Ausgabe: Preis € 6,40
(inkl. 19% MwSt.)

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.