Korrekter Weg um stdout stummzustellen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
snafu
User
Beiträge: 5459
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Montag 3. November 2008, 18:22

Ich lade etwas mit wget herunter, weil ich kein urlopen verwenden möchte, da der kein Resuming von abgebrochenen Downloads unterstützt. Ich möchte jetzt nur Meldungen von stderr angezeigt bekommen. Bisher mache ich das so:

Code: Alles auswählen

from subprocess import call, PIPE

for nr in range(1, 100):
    url = 'http://chaosradio.ccc.de/archive/chaosradio_express_%03d.mp3' % nr
    print 'Lade %s ...' % url
    call(['wget', '-c', url], stdout=PIPE)
Ist das der richtige Weg, wenn ich es plattformübergreifend machen möchte?

Sebastian

EDIT: Ich weiß jetzt gar nicht ob es hundert Sendungen gibt. Ich hatte das nur vor kurzem für einen Python-Anfänger umgeschrieben, da dessen Code ursprünglich so aussah:

Code: Alles auswählen

from os import system

for sendung in range (1,100,1):
    index="00"+str(sendung)
    index=index[-3:]
    link="http://chaosradio.ccc.de/archive/chaosradio_express_"+index+".mp3"
    system("wget -c "+link)
    system("clear")
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 3. November 2008, 18:25

Seit wann ist ``wget`` platformübergreifend verfügbar? Wenn es dir nur um Resume geht, dass geht AFAIR mit Bordmitteln auch.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
Benutzeravatar
snafu
User
Beiträge: 5459
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Montag 3. November 2008, 18:27

Leonidas hat geschrieben:Seit wann ist ``wget`` platformübergreifend verfügbar?
Ich bezog mich mit "plattformübergreifend" eigentlich nur auf das Stummstellen von stdout.
Benutzeravatar
snafu
User
Beiträge: 5459
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Montag 3. November 2008, 18:31

Was die Bordmittel angeht: Ich hatte nur Sachen im Internet gefunden, wo doch einige Zeilen Code nötig waren, um das Ganze zu implementieren. Und es war mir dann etwas zu viel Aufwand, mich da hinein zu lesen.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Montag 3. November 2008, 19:23

http://29a.ch/git/gitweb.cgi?p=lanshark ... =HEAD#l277

Diese Funtktion downloaded eine Datei mit Resume support. :wink:
[url=http://29a.ch/]My Website - 29a.ch[/url]
"If privacy is outlawed, only outlaws will have privacy." - Phil Zimmermann
abgdf

Montag 3. November 2008, 21:15

Seit wann ist ``wget`` platformübergreifend verfügbar?
Schon länger:

http://gnuwin32.sourceforge.net/packages/wget.htm

Gruß
Leonidas
Administrator
Beiträge: 16024
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Montag 3. November 2008, 22:53

abgdf hat geschrieben:
Seit wann ist ``wget`` platformübergreifend verfügbar?
Schon länger:

http://gnuwin32.sourceforge.net/packages/wget.htm
Das ist mir bekannt, schließlich habe ich mir mein Debian 3.1 mit Jidgo-lite auf Windows zusammengebaut. Mir ging es darum, wie wahrscheinlich es ist, so etwas auf dem System vorzufinden. Dürfte wohl so um die 0,1% der Nutzer installiert haben.
My god, it's full of CARs! | Leonidasvoice vs Modvoice
lunar

Montag 3. November 2008, 23:34

Naja, das Ausliefern von wget mit der eigenen Anwendung ist ja nicht verboten, man kann es ja als "Package Data" installieren lassen ;) Ob das angesichts der Möglichkeit, Bordmittel zu nutzen, sinnvoll ist, sei mal dahingestellt ;)
Benutzeravatar
snafu
User
Beiträge: 5459
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dienstag 4. November 2008, 09:05

Ja, aber um mal zur Ausgangsfrage zurückzukommen: In die Pipe leiten und nichts weiter damit machen ist also der übliche Weg?
BlackJack

Dienstag 4. November 2008, 10:48

Nein, Du musst die Ausgabe(n) in eine "Datei" umleiten, die das auch alles "schluckt". Wenn Du `subprocess.PIPE` verwendest, musst Du die Ausgaben auch auslesen, sonst läuft irgend wann der Puffer für die Pipe voll und das Programm blockiert. So ein "schwarzes Loch" bekommt man, wenn man den Dateinamen von `os.devnull` nimmt und damit eine Datei zum schreiben öffnet.
Benutzeravatar
snafu
User
Beiträge: 5459
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dienstag 4. November 2008, 12:11

Danke für den Hinweis mit devnull.

Ich hab jetzt einen simplen Downloader/Resumer mit Python-Bordmitteln gemacht:

http://paste.pocoo.org/show/90095/
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Dienstag 4. November 2008, 12:49

Schreit ja förmlich nach `with`! :D

Zudem würde ich den Datei-Teil in eine den Rest aufrufende Funktion auslagern und das, was momentan an `f.write()` geht, `yield`en.

Naja, dann kann ich's auch gleich umsetzen:

Code: Alles auswählen

from __future__ import with_statement
from os.path import getsize
from urllib2 import Request, urlopen


def download(url, bytes_loaded=0, buffer_size=1048576):  # 1 mb
    request = Request(url)
    request.add_header('Range', 'bytes=%d-' % bytes_loaded)
    data = urlopen(request)
    while True:
        buffer = data.read(buffer_size)
        if buffer == '':
            break
        yield buffer

def resume(url, filename):
    incoming_data = download(url, getsize(filename))
    with open(filename, 'a') as f:
        map(f.write, incoming_data)
Zuletzt geändert von Y0Gi am Dienstag 4. November 2008, 16:42, insgesamt 2-mal geändert.
Benutzeravatar
snafu
User
Beiträge: 5459
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dienstag 4. November 2008, 13:07

Das With-Statement hatte ich diesmal einfach vergessen. Map und Yield sind mir noch nicht so vertraut, aber ich denke daß ich den Sinn von den beiden jetzt einigermaßen verstehe. Mit dem direkten in die Datei schreiben, wollte ich vermeiden daß ich im Extremfall irgendwann hunderte MB an Daten im Speicher liegen habe, bevor das ganze in die Datei geschrieben wird. Und das ist bei deinem Vorschlag doch der Fall, oder?

EDIT: Achso, nee. Es wird ja ein Generator durch yield erzeugt und dann ruft map immer f.write() auf, wenn ein neues MB dazukommt, richtig?

Trotzdem lässt sich IMHO darüber streiten, ob man das jetzt unbedingt in zwei Funktionen zergliedern muss. Und BUFFER_SIZE könnte man wie ich finde genau so gut als Keyword-Argument mit nem Standardwert von 1MB an die Funktion übergeben.
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Dienstag 4. November 2008, 13:44

@YOGi: outfile in Zeile 20 soll doch sicher filename sein?
MfG
HWK
Benutzeravatar
snafu
User
Beiträge: 5459
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dienstag 4. November 2008, 14:06

Und wenn ich dann auch nochmal meinen Senf dazu geben darf: Ich denke nicht, dass man bei der Wahl von Variablen-Namen halbe Romane schreiben muss (bytes_loaded, incoming_data). Das ergibt sich für gewöhnlich aus dem Zusammenhang. Um's mal zu überspitzen: Wie wär's mit incoming_data_from_current_download? ;) Und wenn man erwähnen möchte, dass die Angaben in Bytes sind, dann kann ich das auch in den Docstring schreiben. Zudem sollte man konsequenterweise "temp" in "buffer" umbenennen, wenn man weiter oben auch BUFFER_SIZE sagt.
Antworten