PDF-Version - freiesMagazin
PDF-Version - freiesMagazin
PDF-Version - freiesMagazin
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Python – Teil 10: Kurzer Prozess von Daniel Nögel<br />
Im letzten Teil der Python-Reihe (siehe<br />
<strong>freiesMagazin</strong> 10/2011 [1]) wurde die<br />
urllib-Bibliothek vorgestellt und damit<br />
ein Client für den FileHoster BayFiles.com<br />
implementiert. In diesem Teil soll<br />
das subprocess-Modul vorgestellt werden,<br />
mit dem sich Prozesse starten, Rückgabewerte<br />
auslesen und Pipes umsetzen lassen.<br />
Besprechung der Übung<br />
Zunächst soll aber die im letzten Teil vorgeschlagene<br />
Aufgabe besprochen werden. Umgesetzt<br />
werden sollte eine Download-Funktion mit Fortschrittsanzeige,<br />
die es auch erlaubt, begonnene<br />
Downloads fortzusetzen.<br />
Eine fertige Beispiellösung findet sich bei<br />
GitHub [2]. Einige Besonderheiten sollen im Folgenden<br />
besprochen werden.<br />
In Zeile 12 wird die Zieldatei im Modus ab geöffnet.<br />
Dies bedeutet, dass die Datei binär geöffnet<br />
wird und neue Daten angehängt werden<br />
(append). Wenn die Zieldatei bereits vorhanden<br />
war (resume in Zeile 11 also den Wert True zugewiesen<br />
bekommen hat), wird in Zeile 15/16 zunächst<br />
die aktuelle Dateigröße ermittelt. Dies wäre<br />
auch mit der Funktion os.path.getsize möglich,<br />
da die Datei hier aber bereits geöffnet vorliegt,<br />
wird mit dem Aufruf fh.seek(0, 2) die Position<br />
auf Byte 0 relativ zum Ende der Datei gesetzt<br />
und die Position (und damit die Größe) mit<br />
fh.tell() ermittelt.<br />
Diese Größenangabe wird in den Zeilen 17/18<br />
genutzt, um einen HTTP-Request zu erzeugen,<br />
der die restliche Datei vom Server anfordert.<br />
Der entsprechende Eintrag im HTTP-Header<br />
lautet dann beispielsweise Range: bytes=100-.<br />
Wenn der Fehler 416 geworfen wird, bedeutet<br />
dies, dass die lokale Datei bereits vollständig ist<br />
und der Server keine weiteren Daten bereit hält.<br />
In diesem Fall gilt der Download als abgeschlossen<br />
(Zeilen 22-25).<br />
In den Zeilen 27-34 wird zunächst die Gesamtlänge<br />
des Downloads ermittelt. Durch die Verwendung<br />
des Range-Headers liefert der Server<br />
auf die Frage nach Content-Length allerdings<br />
lediglich die Restgröße des Downloads zurück,<br />
sodass die Größe der bereits heruntergeladenen<br />
Daten hinzuaddiert werden muss (Zeile 28). Tritt<br />
hierbei ein Fehler auf, wird die Größe pauschal<br />
auf 999999999 Bytes festgelegt. Eine Lösung,<br />
die hier auf Grund der Kürze gewählt wurde.<br />
Schöner wäre es beispielsweise, in diesen Fällen<br />
die Größe auf -1 zu setzen und weiter unten im<br />
Code statt einer Fortschrittsanzeige die Meldung<br />
„Gesamtgröße konnte nicht ermittelt werden“ anzuzeigen.<br />
Der Code-Block in den Zeilen 35-41 wird ausgeführt,<br />
wenn die Zieldatei noch nicht vorhanden<br />
war. Auch hier wird die Download-Größe ermittelt<br />
und im Fehlerfall auf 999999999 gesetzt.<br />
In den Zeilen 43-49 findet der eigentliche Download<br />
statt. Der Ausdruck while content ist so<br />
PROGRAMMIERUNG<br />
lange wahr, wie der Aufruf wh.read(blocksize)<br />
in den Zeilen 43 und 46 Daten vom Server zurückliefert<br />
und an den Namen content bindet.<br />
Die gelesenen Daten werden mit einem Zähler<br />
hochgezählt (Zeile 45) und in die Zieldatei geschrieben<br />
(Zeile 46). In den Zeilen 47 und 48 wird<br />
schließlich – wie schon im letzten Teil dieser Einführung<br />
– eine sehr einfache Fortschrittsanzeige<br />
umgesetzt.<br />
Da nicht jeder Server die Anfrage Content-<br />
Length unterstützt und auch nicht jeder Server<br />
den Range-Header berücksichtigt, bietet dieses<br />
Vorgehen insgesamt durchaus Spielraum für<br />
Fehler und Probleme. Dennoch wird durch das<br />
Skript veranschaulicht, wie man einen derartigen<br />
HTTP-Download mit Fortsetzen-Funktion prinzipiell<br />
umsetzen würde.<br />
subprocess<br />
Das subprocess-Modul [3] ist ein recht mächtiges<br />
Werkzeug rund um das Erzeugen von Prozessen.<br />
Damit lassen sich nicht nur Prozesse<br />
ausführen, sondern auch Rückgabewerte und<br />
Fehler auslesen, Eingaben senden und Pipes erzeugen.<br />
Es stellt damit eine wichtige Alternative<br />
zu der Funktion os.system dar, die von Anfängern<br />
gerne genutzt wird, von der aber sogar in<br />
der offiziellen Python-Dokumentation abgeraten<br />
wird [4].<br />
Statt also beispielsweise einen neuen Tab im<br />
Firefox auf diese Weise zu öffnen<br />
© <strong>freiesMagazin</strong> CC-BY-SA 3.0 Ausgabe 12/2011 40