Bilder downloaden und umbenennen

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.
Antworten
vogti
User
Beiträge: 31
Registriert: Mittwoch 21. Januar 2009, 21:53
Kontaktdaten:

Hallo,
ich habe eine Datei 'bilder', welche den zukünftigen Bildnamen und eine dazugehörige URL getrennt von einem Trennzeichen (#!) enthält:
Mein Programm soll das Bild, welches die URL angibt herunter laden und das Bild mit dem Namen (vor dem #!) umbenennen. Hier mein Versuch:
[

Code: Alles auswählen

# -*- coding: cp1252 -*-
import pycurl
def speicher_bild(name,url):
    f = open('pics1/%s.jpg' % (name), 'w') # Öffnen einer Datei name.jpg
    c = pycurl.Curl() # Optionen für cURL
    c.setopt(pycurl.URL, url) # Angabe der URL
    c.setopt(pycurl.VERBOSE, 1)
    c.setopt(pycurl.POST, 0)
    c.setopt(c.NOPROGRESS, 0)
    c.setopt(c.FOLLOWLOCATION, 1)
    c.setopt(c.MAXREDIRS, 5)
    c.setopt(c.WRITEDATA, f) # Nach dem Herunterladen in die Datei name.jpg schreiben

    c.perform()
    c.close()
       
    f.seek(0)
    f.close()
    
def name_bild():
    name=''
    url=''
    datei = open('bilder', 'r')
    weiter = True
    while weiter:
        line = datei.readline()
        if len(line) == 0:
            weiter = False
            break
        else:
            a=line.find('#!')
            for i in range (0,a): # Namen auslesen
                name=name+line[i]
            print name
            
            b=line.find('\n')
            for l in range (a+2,b): # URL auslesen
                url=url+line[l]
            print url 
            speicher_bild(name,url) # Namen und URL an speicher_bild() übergeben
            name=''
            url=''

execute=name_bild()
Die Bilddateien werden erstellt, jedoch irgendwie falsch: In diesem Konkreten Beispiel wird ein Bild halb geladen, bei einem wird nur die Datei erstellt und das andere wird zwar beschrieben, ist jedocch scheinbar falsch, da es nicht gelesen werden kann.

Jemand eine Idee, was ich falsch mache? Glaube, dass bei speicher_bild() etwas nicht stimmt. Namen und URL gibt er ja richtig aus!
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Versuch doch erstmal die ``urllib`` statt curl.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Dies müsste eigentlich (ich habe es nicht ausprobiert) machen, was du willst:

Code: Alles auswählen

for line in open("bilder"):
    name, url = line.split("#!", 1)
    urllib.retrieve(url, name + ".jpg")
Stefan

PS: Warum dein Code nicht tut, kann ich nur raten. Du speicherst jedenfalls die Bilder nicht binär sondern als Text, was unter Windows nicht funktioniert. Das `seek()` finde ich auch suspekt. Ich denke nicht, dass du pycurl brauchst und auch die while-Schleife mit der überflüssigen Boolschen Variable ist komisch.
Zuletzt geändert von sma am Mittwoch 18. März 2009, 11:33, insgesamt 1-mal geändert.
Benutzeravatar
lutz.horn
User
Beiträge: 205
Registriert: Dienstag 8. November 2005, 12:57
Wohnort: Pforzheim

Das klingt für mich nach einem klassichen Fall für ein Shell-Skript.

Code: Alles auswählen

$ cat in | sed -e "s/\#\!/ /" | while read filename url ; do wget -O $filename $url; done
Das hat zwar mit Python nichts zu tun, funkioniert aber.
Benutzeravatar
lutz.horn
User
Beiträge: 205
Registriert: Dienstag 8. November 2005, 12:57
Wohnort: Pforzheim

Ich liebe List-Comprehension:

Code: Alles auswählen

import urllib
[urllib.urlretrieve(url, name) for name, url in
    [line.split("#!", 1) for line in
        open("in")]]
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Man sollte aber anmerken dass es nicht der feine Stil ist, LCs nur wegen ihrer Seiteneffekte zu verwenden.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
lutz.horn
User
Beiträge: 205
Registriert: Dienstag 8. November 2005, 12:57
Wohnort: Pforzheim

Klar, auch wenn die unschöne Nebenwirkung nur in der äußersten Liste auftritt. Der Aufruf von opne() hat ja auch eine Nebenwirkung, liefert aber das, was benötigt wird . Ein übliches Problem von Funktionaler Programmierung.

Schön ist aber, dass es in Python eben doch mehr als einen Weg gibt :)
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

lutz.horn hat geschrieben:Schön ist aber, dass es in Python eben doch mehr als einen Weg gibt :)
Dass es mehrere Wege gibt hat nie jemand bezweifelt. Es ging um "one *best* way", und lisp-like lc ist sicher nicht sonderlich pythonic.
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

lutz.horn hat geschrieben:Klar, auch wenn die unschöne Nebenwirkung nur in der äußersten Liste auftritt. Der Aufruf von opne() hat ja auch eine Nebenwirkung, liefert aber das, was benötigt wird . Ein übliches Problem von Funktionaler Programmierung.
Tritt aber in funktionalen Sprachen nicht auf ;)

Code: Alles auswählen

with open("in") as input:
    for line in input:
         urllib.urlretrieve(*reversed(line.split("#!", 1)))
lunar

lutz.horn hat geschrieben:Ich liebe List-Comprehension:

Code: Alles auswählen

import urllib
[urllib.urlretrieve(url, name) for name, url in
    [line.split("#!", 1) for line in
        open("in")]]

Code: Alles auswählen

with open('in') as stream:
    for line in stream:
         urllib.urlretrieve(*reversed(line.split('#!', 1)))
Auch nicht länger als dein Code, aber ohne eine überflüssige LC
Benutzeravatar
lutz.horn
User
Beiträge: 205
Registriert: Dienstag 8. November 2005, 12:57
Wohnort: Pforzheim

Um Länge und die genaue Anzahl der LCs geht es mir gar nicht. Ich finde lediglich interessant, dass es mit Python eben auch möglich ist, in einem Stil zu programmieren, bei dem die Schachtelung genau umgedreht ist. Das sieht halt mehr nach Lisp aus :)
lunar

lutz.horn hat geschrieben:Um Länge und die genaue Anzahl der LCs geht es mir gar nicht. Ich finde lediglich interessant, dass es mit Python eben auch möglich ist, in einem Stil zu programmieren, bei dem die Schachtelung genau umgedreht ist.
Deswegen ist das aber noch lange nicht elegant oder überhaupt sinnvoll.
Das sieht halt mehr nach Lisp aus :)
Sieht das hier aus wie ein LISP-Forum? ;)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

lutz.horn hat geschrieben:Das sieht halt mehr nach Lisp aus :)
Finde ich nicht. In Lisp programmiert man über Komposition von Funktionen, du programmierst über Komposition von Syntaktischem Zucker.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
vogti
User
Beiträge: 31
Registriert: Mittwoch 21. Januar 2009, 21:53
Kontaktdaten:

Fehler Nummer 1:
In der Datei 'bilder' sind auch URLs zu Bildern anderer Formate als nur 'jpg'. Das heißt Heruntergeladene *.pngs werden natürlich nicht richtig angezeigt, wenn ich sie als *.jpg speichere. Das muss also überdacht werden (z.B. muss der Dateityp übermittelt werden).

Fehler Nummer2:
Ich denke, dass sma mit seiner Behauptung recht hat, dass ich Bilder nicht einfach so als Text speichern kann. Ich muss also eine Methode finden, das Bild direkt binär downzuloaden.

Und eine generelle Frage, weils mir schon häufig in diesem Forum aufgefallen ist: Warum wird so selten auf die Frage direkt geantwortet?
Wenn ich eine Frage bezüglich cURL frage, dann habe ich mir doch dabei was gedacht. Antworten ála "Nutz doch urllib" sind da nicht so sinnvoll. Auch die LISP/bla-Diskussion ist ziemlich OT und hilft nichtmal ansatzweise zur Lösung des Problems.

Dennoch danke ich euch, dass ihr euch die Zeit genommen habt.
Benutzeravatar
BlackVivi
User
Beiträge: 762
Registriert: Samstag 9. Dezember 2006, 14:29
Kontaktdaten:

Du hast in deinem Post nicht erwähnt, wieso du Curl benutzen willst - man geht dann davon aus, dass du urllib nicht kennst.

Die Daten von urlretrieve sind binär, wenn du auch binäre Daten haben möchtest, Bilder zum Beispiel.

Die Sache mit der Dateiendung lässt sich auch simpel lösen. Du schaust dir vorher die URL an und splittest die Endung (dafür gibts auch eine Funktion in urllib). Die hängst du dann hinten an...

filename + ext --> Das was du haben willst.

Ich versteh nicht, wieso du gleich so stark angreifst...
vogti
User
Beiträge: 31
Registriert: Mittwoch 21. Januar 2009, 21:53
Kontaktdaten:

Code: Alles auswählen

# -*- coding: cp1252 -*-
import urllib
import os
def speicher_bild(name,url):
    if os.path.exists('pics1/'+name+'.jpg') != True:
        urllib.urlretrieve(url, 'pics1/'+name+'.jpg')
    else:
        pass
    
def name_bild():
    name=''
    url=''
    datei = open('bilder', 'r')
    weiter = True
    while weiter:
        line = datei.readline()
        if len(line) == 0:
            weiter = False
            break
        else:
            daten = line.split('#!')
            name = daten[0]
            url = daten[1]
            print name, url
            if ((name) or (url) != ''):
                speicher_bild(name,url)
            else:
                pass

execute=name_bild()
Mit urllib funktioniert es zwar, jedoch würde ich lieber ein pycURL äquivalent nutzen (Leider kommt noch eine Fehlermeldung, wenn url leer ist. Weiß noch nicht genau, wie man das wegbekommt...). Danke BlackVivi für den Tip mit urlretrieve!

Übrigens wollte ich keineswegs irgendwen angreifen.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Nutze os.path.join zum Zusammensetzen von Pfaden, == oder != True / False ist unnötig, da sowieso der Ausdruck ausgewertet + bool() darauf angewendet wird und if somit einen Wahrheitswert bekommt, den man nicht nochmal auf True prüfen muss, weiter als Variable ist bei Nutzung von break unnötig (while True: ...), den else Block im if in name_bild würd ich weglassen und einfach mit break aus dem Code springen (wie du es eh schon machst). Und (nach PEP8) zwischen dem "=" bei Zuweisungen außerhalb von Funktions-Keyword-Argumenten immer ein Leerzeichen, sofern du dich daran halten willst. (Kann sowieso nicht verstehen, warum Code manchmal so fürchterlich unaufgeräumt und inkonsistent aussieht - mich würd das selber ziemlich nerven (@vogti, dein Code ist nicht gemeint ;))). Ach, und Namen, die man nur (zur Klarheit) "bekannt machen" will, würd ich einfach None zuweisen anstatt eine leere Instanz der entsprechenden Klasse. Dann gibts auch nen Error, wenn man mal einen vergisst und None irgendwo herumfliegen hat.
BlackJack

@vogti: Ergänzend zu str1442: Ich würde Namen gar nicht "bekannt machen", sondern erst dort verwenden, wo sie auch wirklich gebraucht werden. Sollte das zu unübersichtlich werden, ist das oft ein gutes Zeichen dafür, dass man zu viele lokale Namen hat und eventuell die Funktion aufteilen sollte.

``pass`` in ``if``/``else``-Konstrukten ist überflüssig. Das kann man immer auch ohne ``pass`` ausdrücken. In diesem Fall kann man die ``else``-Zweige einfach weglassen.

Man sollte Wiederholungen im Quelltext vermeiden. Den Dateinamen braucht man nur einmal zusammensetzen.

Dateien, die man öffnet, sollte man auch wieder schliessen. Am besten in einem ``finally``-Block oder mit einer ``with``-Anweisung um sicher zu gehen.

Die ``while``-Schleife drückt man "pythonischer" als ``for``-Schleife über das Dateiobjekt aus. Dateien sind "iterable". Dann kann man sich auch die Abbruchbedingung mit dem ``break`` sparen. Die ``for``-Schleife endet automatisch am Dateiende.

`daten` kann man sich sparen, wenn man das Ergebnis von `split()` gleich den richtigen Namen zuweist.

Die Bedingung vor dem Aufruf von `speicher_bild()` ist sehr eigenartig geklammert. Die kann man alle weglassen, ohne dass sich etwas ändert. Dann bleibt aber immer noch der Eindruck, dass Du da etwas falsch verstehst. Es werden dort nicht `name` und `url` explizit mit ``!= ''`` verglichen, sondern nur `url`. Das macht nur deshalb keinen Unterschied weil ``if name`` im Grunde das gleiche ist wie ``if name != ''``. Zeichenketten sind "falsch" wenn sie leer sind und "wahr" sonst. Ich weiss auch nicht ob ``or`` die richtige Verknüpfung ist, denn ich hätte hier eher erwartet, das gespeichert werden soll, wenn `name` *und* `url` nicht leer sind!?

`name_bild()` hat keinen Rückgabewert, es macht also wenig Sinn das implizite `None` an `execute` zu binden.

Letztendlich sähe das Ganze dann so aus (ungetestet):

Code: Alles auswählen

def speicher_bild(name, url):
    jpeg_name = os.path.join('pics1', name + '.jpg')
    if not os.path.exists(jpeg_name):
        urllib.urlretrieve(url, jpeg_name)

def name_bild():
    with open('bilder', 'r') as datei:
        for line in datei:
            name, url = line.split('#!')
            print name, url
            if name and url:
                speicher_bild(name, url)

name_bild()
Antworten