Seite 1 von 1

Bilder downloaden und umbenennen

Verfasst: Mittwoch 18. März 2009, 10:17
von vogti
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!

Verfasst: Mittwoch 18. März 2009, 11:03
von Leonidas
Versuch doch erstmal die ``urllib`` statt curl.

Verfasst: Mittwoch 18. März 2009, 11:05
von sma
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.

Verfasst: Mittwoch 18. März 2009, 11:28
von lutz.horn
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.

Verfasst: Mittwoch 18. März 2009, 11:37
von lutz.horn
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")]]

Verfasst: Mittwoch 18. März 2009, 11:44
von Leonidas
Man sollte aber anmerken dass es nicht der feine Stil ist, LCs nur wegen ihrer Seiteneffekte zu verwenden.

Verfasst: Mittwoch 18. März 2009, 11:49
von lutz.horn
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 :)

Verfasst: Mittwoch 18. März 2009, 12:10
von keppla
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.

Verfasst: Mittwoch 18. März 2009, 12:11
von audax
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)))

Verfasst: Mittwoch 18. März 2009, 12:11
von 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

Verfasst: Mittwoch 18. März 2009, 12:21
von lutz.horn
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 :)

Verfasst: Mittwoch 18. März 2009, 12:27
von 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? ;)

Verfasst: Mittwoch 18. März 2009, 13:03
von Leonidas
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.

Verfasst: Samstag 21. März 2009, 23:23
von vogti
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.

Verfasst: Sonntag 22. März 2009, 00:58
von BlackVivi
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...

Verfasst: Sonntag 22. März 2009, 02:01
von vogti

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.

Verfasst: Sonntag 22. März 2009, 05:03
von str1442
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.

Verfasst: Sonntag 22. März 2009, 08:09
von 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()