Wie finde ich den MIME-Typ einer Datei in Python?

193

Angenommen, Sie möchten eine Reihe von Dateien irgendwo speichern, beispielsweise in BLOBs. Angenommen, Sie möchten diese Dateien über eine Webseite verteilen und den Client automatisch die richtige Anwendung / den richtigen Viewer öffnen lassen.

Annahme: Der Browser ermittelt anhand des MIME-Headers (Inhaltstyp?) In der HTTP-Antwort, welche Anwendung / welcher Viewer verwendet werden soll.

Basierend auf dieser Annahme möchten Sie zusätzlich zu den Bytes der Datei auch den MIME-Typ speichern.

Wie würden Sie den MIME-Typ einer Datei finden? Ich bin derzeit auf einem Mac, aber dies sollte auch unter Windows funktionieren.

Fügt der Browser diese Informationen hinzu, wenn die Datei auf der Webseite veröffentlicht wird?

Gibt es eine ordentliche Python-Bibliothek, um diese Informationen zu finden? Ein WebService oder (noch besser) eine herunterladbare Datenbank?

Daren Thomas
quelle

Antworten:

217

Die von toivotuo vorgeschlagene Python-Magic-Methode ist veraltet. Der aktuelle Trunk von Python-magic befindet sich bei Github und basierend auf der dortigen Readme-Datei wird der MIME-Typ wie folgt ermittelt.

# For MIME types
import magic
mime = magic.Magic(mime=True)
mime.from_file("testdata/test.pdf") # 'application/pdf'
Simon Zimmermann
quelle
17
danke für den Kommentar! Bitte beachten Sie, dass "oben" ein schwieriges Konzept im Stackoverflow ist, da die Reihenfolge nach Stimmen gruppiert und innerhalb der Gruppen zufällig angeordnet ist. Ich vermute, Sie beziehen sich auf die Antwort von @ toivotuo.
Daren Thomas
1
Ja, ich hatte zum Zeitpunkt des Schreibens dieser Antwort nicht genügend "Punkte", um Kommentare zu erstellen. Aber ich hätte es wahrscheinlich als Kommentar schreiben sollen, damit der @toivotuo seine Frage hätte bearbeiten können.
Simon Zimmermann
1
rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL: darwinsys.com/file Zusammenfassung: Python-Bindungen für die libmagische API rpm -qf / usr / bin / file -i Name: Datei URL: darwinsys.com/file python-magic von darwinsys.com/file, die mit Linux geliefert wird Fedora funktioniert wie bei @ toivotuo. Und scheint mehr Hauptstrom.
Sérgio
7
Beachten Sie, dass sich das Debian / Ubuntu-Paket namens Python-Magic vom gleichnamigen Pip-Paket unterscheidet. Beide sind import magicaber inkompatible Inhalte. Weitere Informationen finden Sie unter stackoverflow.com/a/16203777/3189 .
Hamish Downer
1
Wie ich zu toivotuos Antwort kommentiert habe, ist sie nicht veraltet! Sie sprechen von einer anderen Bibliothek. Können Sie diese Aussage bitte in Ihrer Antwort entfernen oder ersetzen? Derzeit ist es sehr schwierig, die beste Lösung zu finden.
Bodo
86

Das Mimetypes-Modul in der Standardbibliothek ermittelt / errät den MIME-Typ aus einer Dateierweiterung.

Wenn Benutzer Dateien hochladen, enthält der HTTP-Beitrag neben den Daten den MIME-Typ der Datei. Beispielsweise stellt Django diese Daten als Attribut des UploadedFile- Objekts zur Verfügung.

Dave Webb
quelle
12
Wenn die Dateien in BLOBs gespeichert sind, wie in der Frage angegeben, kennen Sie möglicherweise die Dateierweiterung nicht.
Mechanische Schnecke
55
Dateierweiterungen sind keine zuverlässige Methode zur Bestimmung des MIME-Typs.
Cerin
12
import mimetypes mimetypes.MimeTypes().guess_type(filename)[0]
Jonathan
4
In Python 3.6 funktioniert dies:mimetypes.guess_type(path_file_to_upload)[1]
JinSnow
3
Während @cerin Recht hat, dass Dateierweiterungen nicht zuverlässig sind, habe ich gerade festgestellt, dass die Genauigkeit von python-magic(wie in der oberen Antwort vorgeschlagen) noch geringer ist, wie von github.com/s3tools/s3cmd/issues/198 bestätigt . Also, mimetypesscheint ein besserer Kandidat für mich zu sein.
Danqing
46

Ein zuverlässigerer Weg als die Verwendung der Mimetypes-Bibliothek wäre die Verwendung des Python-Magic-Pakets.

import magic
m = magic.open(magic.MAGIC_MIME)
m.load()
m.file("/tmp/document.pdf")

Dies entspricht der Verwendung von Datei (1).

Auf Django könnte man auch sicherstellen, dass der MIME-Typ mit dem von UploadedFile.content_type übereinstimmt.

toivotuo
quelle
2
Siehe Simon Zimmermanns Beitrag für eine aktualisierte Verwendung von Python-Magie
Daren Thomas
@DarenThomas: Wie in Mammadoris Antwort erwähnt, ist diese Antwort nicht veraltet und unterscheidet sich von der Lösung von Simon Zimmermann. Wenn Sie das Dateidienstprogramm installiert haben, können Sie diese Lösung wahrscheinlich verwenden. Es funktioniert bei mir mit Datei-5.32. Auf Gentoo muss auch das Python USE-Flag für das Dateipaket aktiviert sein.
Bodo
35

Das scheint sehr einfach zu sein

>>> from mimetypes import MimeTypes
>>> import urllib 
>>> mime = MimeTypes()
>>> url = urllib.pathname2url('Upload.xml')
>>> mime_type = mime.guess_type(url)
>>> print mime_type
('application/xml', None)

Bitte beziehen Sie sich auf Old Post

Update - Gemäß dem @ Garrets-Kommentar ist es in Python 3 einfacher:

import mimetypes
print(mimetypes.guess_type("sample.html"))
Laxmikant Ratnaparkhi
quelle
4
Ich glaube nicht, dass die Urllib in Ihrem Beispiel erforderlich ist.
BrotherJack
5
Für Python 3.X ersetzen Sie die importierte Urllib durch die Importanforderung von urllib. Und dann verwenden Sie "Anfrage" anstelle von Urllib
Arjun Thakur
1
Funktioniert auch für Python 2.7
Jay Modi
Die Lösung von @ oetzi verwendet dieses Modul, ist jedoch einfacher.
Garrett
11

Es gibt 3 verschiedene Bibliotheken, die libmagic umschließen.

2 davon sind auf pypi verfügbar (damit die Pip-Installation funktioniert):

  • filemagisch
  • Python-Magie

Und eine andere, ähnlich wie Python-Magie, ist direkt in den neuesten libmagischen Quellen verfügbar und die, die Sie wahrscheinlich in Ihrer Linux-Distribution haben.

In Debian handelt es sich bei dem Paket python-magic um dieses Paket, das wie oben beschrieben verwendet wird und nicht überholt ist, wie Simon Zimmermann (IMHO) sagte.

Es scheint mir eine andere Einstellung zu sein (vom ursprünglichen Autor von libmagic).

Schade, dass es nicht direkt auf pypi verfügbar ist.

Mammadori
quelle
Ich habe der pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
Einfachheit halber
10

in Python 2.6:

mime = subprocess.Popen("/usr/bin/file --mime PATH", shell=True, \
    stdout=subprocess.PIPE).communicate()[0]
apito
quelle
6
Dies ist nicht fileerforderlich , da der Befehl im Grunde nur ein Wrapper um libmagic ist. Sie können auch einfach die Python-Bindung (Python-Magie) verwenden, wie in Simons Antwort.
Mechanische Schnecke
6
Das hängt vom Betriebssystem ab. Unter Mac OS X haben Sie beispielsweise "Datei", aber in der normalen Umgebung nicht libmagisch.
Rptb1
9

Update 2017

Sie müssen nicht zu Github gehen, es ist auf PyPi unter einem anderen Namen:

pip3 install --user python-magic
# or:
sudo apt install python3-magic  # Ubuntu distro package

Der Code kann ebenfalls vereinfacht werden:

>>> import magic

>>> magic.from_file('/tmp/img_3304.jpg', mime=True)
'image/jpeg'
Gringo Suave
quelle
können Sie das gleiche für js oder CSS-Datei tun?
Kumbhanibhavesh
Sicher warum nicht??
Gringo Suave
8

Python-Bindungen an libmagic

All die unterschiedlichen Antworten zu diesem Thema sind sehr verwirrend, daher hoffe ich, mit diesem Überblick über die verschiedenen Bindungen von libmagic etwas mehr Klarheit zu schaffen. Zuvor gab Mammadori eine kurze Antwort mit der Auflistung der verfügbaren Option.

libmagic

Bei der Bestimmung des MIME-Typs einer Datei wird einfach das Tool Ihrer Wahl aufgerufen fileund sein Back-End aufgerufen libmagic. (Siehe die Projekthomepage .) Das Projekt wird in einem privaten CVS-Repository entwickelt, aber auf Github befindet sich ein schreibgeschützter Git-Spiegel .

Dieses Tool, das Sie benötigen, wenn Sie eine der libmagischen Bindungen mit Python verwenden möchten, enthält bereits eigene Python-Bindungen file-magic. Es gibt nicht viel dedizierte Dokumentation für sie, aber Sie können immer einen Blick auf die Manpage der C-Bibliothek werfen : man libmagic. Die grundlegende Verwendung wird in der Readme-Datei beschrieben :

import magic

detected = magic.detect_from_filename('magic.py')
print 'Detected MIME type: {}'.format(detected.mime_type)
print 'Detected encoding: {}'.format(detected.encoding)
print 'Detected file type name: {}'.format(detected.name)

Abgesehen davon können Sie die Bibliothek auch verwenden, indem Sie ein MagicObjekt erstellen , magic.open(flags)wie in der Beispieldatei gezeigt .

Sowohl toivotuo als auch ewr2san verwenden diese file-magicim fileTool enthaltenen Bindungen . Sie nehmen fälschlicherweise an, dass sie das python-magicPaket verwenden. Dies scheint darauf hinzudeuten, dass sich das Python-Modul auf das vorherige bezieht , wenn beide fileund python-magicinstalliert sind magic.

Python-Magie

Dies ist die Bibliothek, über die Simon Zimmermann in seiner Antwort spricht und die auch von Claude COULOMBE sowie Gringo Suave verwendet wird .

filemagisch

Hinweis : Dieses Projekt wurde zuletzt im Jahr 2013 aktualisiert!

Da diese Bibliothek auf derselben c-api basiert, hat sie eine gewisse Ähnlichkeit mit file-magicder in libmagic. Es wird nur von Mammadori erwähnt und keine andere Antwort verwendet es.

Bodo
quelle
7

Die Methode von @toivotuo hat unter python3 für mich am besten und zuverlässigsten funktioniert. Mein Ziel war es, komprimierte Dateien zu identifizieren, die keine zuverlässige .gz-Erweiterung haben. Ich habe python3-magic installiert.

import magic

filename = "./datasets/test"

def file_mime_type(filename):
    m = magic.open(magic.MAGIC_MIME)
    m.load()
    return(m.file(filename))

print(file_mime_type(filename))

Für eine komprimierte Datei wird Folgendes zurückgegeben: application / gzip; Zeichensatz = binär

für eine entpackte txt-Datei (iostat-Daten): text / plain; Zeichensatz = us-ascii

für eine TAR-Datei: application / x-tar; Zeichensatz = binär

für eine bz2-Datei: application / x-bzip2; Zeichensatz = binär

und zu guter Letzt für mich eine .zip-Datei: application / zip; Zeichensatz = binär

ewr2san
quelle
6

Sie haben nicht angegeben, welchen Webserver Sie verwendet haben, aber Apache hat ein nettes kleines Modul namens Mime Magic, mit dem Sie den Dateityp bestimmen können, wenn Sie dazu aufgefordert werden. Es liest einen Teil des Dateiinhalts und versucht anhand der gefundenen Zeichen herauszufinden, welcher Typ es ist. Und wie Dave Webb erwähnte, funktioniert das MimeTypes-Modul unter Python, vorausgesetzt, eine Erweiterung ist praktisch.

Wenn Sie auf einer UNIX-Box sitzen, können Sie alternativ sys.popen('file -i ' + fileName, mode='r')den MIME-Typ abrufen. Windows sollte einen entsprechenden Befehl haben, aber ich bin mir nicht sicher, was es ist.

Akdom
quelle
7
Heutzutage können Sie einfach subprocess.check_output (['Datei', '-b', '--mime', Dateiname])
Nathan Villaescusa
Es gibt wirklich keinen Grund, auf ein externes Tool zurückzugreifen, wenn Python-Magic das Gleiche tut, alles verpackt und gemütlich.
Verdammter
6

Python 3 ref: https://docs.python.org/3.2/library/mimetypes.html

mimetypes.guess_type (url, strict = True) Erraten Sie den Typ einer Datei anhand ihres Dateinamens oder ihrer URL, die durch die URL angegeben wird. Der Rückgabewert ist ein Tupel (Typ, Codierung), wobei type None ist, wenn der Typ nicht erraten werden kann (fehlendes oder unbekanntes Suffix), oder eine Zeichenfolge der Form 'type / subtype', die für einen MIME-Header vom Inhaltstyp verwendet werden kann.

Die Codierung ist Keine für keine Codierung oder den Namen des zum Codieren verwendeten Programms (z. B. Komprimieren oder GZIP). Die Codierung eignet sich zur Verwendung als Content-Encoding-Header, nicht als Content-Transfer-Encoding-Header. Die Zuordnungen sind tabellengesteuert. Bei Codierungssuffixen wird zwischen Groß- und Kleinschreibung unterschieden. Typensuffixe werden zuerst mit Groß- und Kleinschreibung und dann ohne Berücksichtigung von Groß- und Kleinschreibung ausprobiert.

Das optionale strikte Argument ist ein Flag, das angibt, ob die Liste der bekannten MIME-Typen nur auf die bei IANA registrierten offiziellen Typen beschränkt ist. Wenn strict True ist (Standardeinstellung), werden nur die IANA-Typen unterstützt. Wenn strict False ist, werden auch einige zusätzliche nicht standardmäßige, aber häufig verwendete MIME-Typen erkannt.

import mimetypes
print(mimetypes.guess_type("sample.html"))
oetzi
quelle
4

In Python 3.x und Webapp mit URL zu der Datei, die keine Erweiterung oder eine gefälschte Erweiterung haben konnte. Sie sollten Python-Magic mit installieren

pip3 install python-magic

Unter Mac OS X sollten Sie libmagic auch mit installieren

brew install libmagic

Code-Auszug

import urllib
import magic
from urllib.request import urlopen

url = "http://...url to the file ..."
request = urllib.request.Request(url)
response = urlopen(request)
mime_type = magic.from_buffer(response.readline())
print(mime_type)

Alternativ können Sie eine Größe in den Lesevorgang eingeben

import urllib
import magic
from urllib.request import urlopen

url = "http://...url to the file ..."
request = urllib.request.Request(url)
response = urlopen(request)
mime_type = magic.from_buffer(response.read(128))
print(mime_type)
Claude COULOMBE
quelle
Wird es die ganze Datei laden?
凡 凡
Nein, es ist ein Stream, also normalerweise nur wenige Bytes.
Claude COULOMBE
Ich habe von response.readline () oder response.read (128) bearbeitet. Danke!
Claude COULOMBE
2

Ich versuche zuerst die Bibliothek der Mimetypen. Wenn es nicht funktioniert, verwende ich stattdessen Python-Magic Libary.

import mimetypes
def guess_type(filename, buffer=None):
mimetype, encoding = mimetypes.guess_type(filename)
if mimetype is None:
    try:
        import magic
        if buffer:
            mimetype = magic.from_buffer(buffer, mime=True)
        else:
            mimetype = magic.from_file(filename, mime=True)
    except ImportError:
        pass
return mimetype
Jak Liao
quelle
1

Das Mimetypes-Modul erkennt nur einen Dateityp basierend auf der Dateierweiterung. Wenn Sie versuchen, einen Dateityp einer Datei ohne Erweiterung wiederherzustellen, funktionieren die Mimetypen nicht.

Helder
quelle
3
Ich denke nicht, dass das stimmt. Beim MIME-Typ geht es darum, wie Sie anderen von einem Datenformat erzählen und nicht, wie Sie das Datenformat selbst herausfinden. Wenn Sie ein Tool verwenden, das das Format nur anhand der Erweiterung errät und MIME-Typen druckt, können Sie dieses Tool nicht verwenden, wenn keine Dateierweiterungen vorhanden sind. Es gibt aber auch andere Möglichkeiten, das Format zu erraten, z. B. durch Überprüfen mit einem Parser.
Erikbwork
0

Ich habe viele Beispiele ausprobiert, aber mit Django spielt Mutagen gut.

Beispiel für die Überprüfung, ob Dateien vorhanden sind mp3

from mutagen.mp3 import MP3, HeaderNotFoundError  

try:
    audio = MP3(file)
except HeaderNotFoundError:
    raise ValidationError('This file should be mp3')

Der Nachteil ist, dass Sie nur begrenzt in der Lage sind, Dateitypen zu überprüfen. Dies ist jedoch eine gute Möglichkeit, wenn Sie nicht nur nach Dateitypen suchen, sondern auch auf zusätzliche Informationen zugreifen möchten.

Artem Bernatskyi
quelle
Ich muss auch die Sicherheit überprüfen
Artem Bernatskyi
0

Für Daten vom Typ Byte-Array können Sie magic.from_buffer (_byte_array, mime = True) verwenden.

SuperUser
quelle
0

Ich bin überrascht, dass niemand es erwähnt hat, aber Pylements kann eine fundierte Vermutung über den Mimetyp , insbesondere von Textdokumenten , anstellen .

Pylements ist eigentlich eine Python-Syntax-Hervorhebungsbibliothek, verfügt jedoch über eine Methode, mit der Sie genau erraten können, welcher der 500 unterstützten Dokumenttypen Ihr Dokument ist. dh c ++ vs C # vs Python vs etc.

import inspect

def _test(text: str):
    from pygments.lexers import guess_lexer
    lexer = guess_lexer(text)
    mimetype = lexer.mimetypes[0] if lexer.mimetypes else None
    print(mimetype)

if __name__ == "__main__":
    # Set the text to the actual defintion of _test(...) above
    text = inspect.getsource(_test)
    print('Text:')
    print(text)
    print()
    print('Result:')
    _test(text)

Ausgabe:

Text:
def _test(text: str):
    from pygments.lexers import guess_lexer
    lexer = guess_lexer(text)
    mimetype = lexer.mimetypes[0] if lexer.mimetypes else None
    print(mimetype)


Result:
text/x-python

Jetzt ist es nicht perfekt, aber wenn Sie feststellen müssen, welches von 500 Dokumentformaten verwendet wird, ist dies verdammt nützlich.

Eric McLachlan
quelle
-1

Sie können das imghdr Python-Modul verwenden.

jianpx
quelle
1
Dies ist kein hilfreicher Kommentar, da er weder Beispiele enthält noch wirklich sagt, wie oder warum imghdr hier helfen würde.
Erikbwork
2
Ja ich verstehe das. Es ist über ein Jahr her, aber vielleicht können Sie es trotzdem aktualisieren, weil immer noch Leute wie ich nach dieser Frage suchen. Wenn Sie Hilfe brauchen, können Sie es mir sagen.
Erikbwork
1
Es funktioniert nur für eine sehr begrenzte Liste von Bildtypen. Es hat keine Ahnung von Textdateien, komprimierten Archiven, Dokumentformaten usw.
Tripleee