Jpeg-Download prüfen obs wirklich ein bild ist.

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.
Mal_Block
User
Beiträge: 1
Registriert: Donnerstag 9. Oktober 2008, 13:15

Jpeg-Download prüfen obs wirklich ein bild ist.

Beitragvon Mal_Block » Donnerstag 9. Oktober 2008, 13:25

Hi,
ich möchte mit einem kleinen Script eine jpeg Datei runterladen. Allerding soll überprüft werden ob der download wirklich ein jpeg Bild ist, da oft bei nicht existenten Bildern einfach Errorseiten heruntergeladen werden.
Der Code zum downloaden sieht bis jetzt wie folgt aus:

Code: Alles auswählen

import urllib
   
f =  urllib.urlopen("Hier die Jpeg-Url")
g = f.read()
file = open("Hier der Dateiname", "wb")
file.write(g)
file.close()


Und jetzt hab ich keine Ahnung wie ich die Jpeg Datei überprüfen soll.

Gruß Mal_Block
lunar

Beitragvon lunar » Donnerstag 9. Oktober 2008, 13:36

Wenn du urllib2 nutzt, erhältst du eine Ausnahme, wenn die URL Fehlercodes wie HTTP Not Found zurückliefert. Desweiteren hat die Rückgabe von "urllib2.urlopen" ein Attribut namens "headers", über dessen Methoden "gettype()", "getsubtype()" und "getmaintype()" du den vom Server gesetzt den Content-Type überprüfen kannst. Außerdem hat Python das Modul "imghdr".
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Donnerstag 9. Oktober 2008, 15:45

Ich löse das bisweilen so:

Code: Alles auswählen

MAGIC_NUMBERS = [
    (u'gif', '\x47\x49\x46\x38\x39\x61'),  # or \x47\x49\x46\x38\x37\x61
    (u'jpg', '\xFF\xD8\xFF'),
    (u'png', '\x89\x50\x4e\x47\x0d\x0a\x1a\x0a')]
MAX_BYTES = max(len(mn[1]) for mn in MAGIC_NUMBERS)

def guess_type(data):
    """Try to determine the image type using `magic numbers`_.

    If the type cannot be determined, ``None`` is returned.

    .. _magic numbers:  http://en.wikipedia.org/wiki/Magic_number_%28programming%29
    """
    if not isinstance(data, basestring):
        data = data.read(MAX_BYTES)
    for type_, magic_number in MAGIC_NUMBERS:
        if data.startswith(magic_number):
            return type_


``imghdr`` kannte ich noch nicht, werde dann aber in Zukunft wohl lieber das verwenden. Danke für den Tipp!

Obligatorischer Hinweis: Auf die Richtigkeit des ``Content-Type``-Headers darf man sich natürlich nicht verlassen.
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

Beitragvon Y0Gi » Donnerstag 9. Oktober 2008, 16:44

Holla, ich habe mir gerade das entsprechende Modul angesehen und bin doch unangenehm überrascht vom Quelltext. Komische ASCII-Kästchen-Kommentare, nicht beim direkten Modulaufruf ausgeführte Tests und eine API für die (nicht Unit-)Testfunktionen, bei der die Parameter nichtssagende 1-Zeichen-Namen haben und der zweite auch noch überflüssig ist. Erst dachte ich, der wäre da aus Kompatibilität zu der Signatur von ``what()`` belassen worden, aber dort ist die Reihenfolge vertauscht. Was soll das also?

Weiterhin steht in der (separaten) Doku, der erste Parameter würde sinnigerweise ``filename`` heißen. Der heißt im Modul allerdings ``file``. Gut, den ersten Parameter wird wohl niemand als Keyword-Argument übergeben (Nachtrag: geht auch nicht, da er keinen Defaultwert hat), aber zum Einen ist ``file`` eine schlechte Wahl, die sich mit dem Built-in überschneidet, und zum Anderen bedeuten ``filename`` (String) und ``file`` (file-like-Objekt) für mich zwei sehr unterschiedliche Dinge. Weiterhin darf man sich fragen, warum nicht nur ein Parameter akzeptiert und zwischen diesen beiden sinnvollen Typen durch ``isinstance(f, basestring)`` oder ``hasattr(f, read)`` (o.ä.) unterschieden wird. Nachtrag: OK, es wird unterschieden, allerdings wird kein Unicode-Dateiname akzeptiert und die Doku spricht von ``h`` als "Stream"; in meinem Verständnis (und z. B. auch dem von Werkzeug) ist das ein file-like-Objekt und kein, ja, "slicebares" Objekt.

Da fällt mir das technisch überflüssige ``return None`` am Funktionsende auch schon gar nicht mehr auf ...

</rant>
lunar

Beitragvon lunar » Donnerstag 9. Oktober 2008, 17:12

Tja, ich habe mir den Code dieses Moduls nie angesehen, bei mir hat es immer funktioniert ;)

Was die technische Kritik angeht: Fix it. Bei 161 Zeilen sollte dir das wohl nicht allzu große Mühe bereiten ;)

Btw, "return None" halte ich für sinnvoll, da es explizit anzeigt, dass die Rückgabe dieses Wertes gewünscht ist. Ohne ein explizites "return None" kommt man leicht auf die Idee, dass der Entwickler einfach nur ein Return-Statement vergessen hat, wenn an anderer Stelle in der Funktion ein Wert zurückgegeben wird. Ich persönlich würde "return None" an sich gut heißen, abgesehen davon, dass ich eine Funktion eher so schreiben würde, dass sie nur an einer Stelle einen Namen zurückgibt, der dann halt entsprechend mit None oder einem Mimetype belegt ist.

Wer ist online?

Mitglieder in diesem Forum: Astorek