Comment trouver le type mime d'un fichier en python?

194

Supposons que vous souhaitiez enregistrer un tas de fichiers quelque part, par exemple dans des BLOB. Supposons que vous souhaitiez diffuser ces fichiers via une page Web et que le client ouvre automatiquement l'application / la visionneuse appropriée.

Hypothèse: le navigateur détermine quelle application / quel visualiseur utiliser par l'en-tête mime-type (content-type?) Dans la réponse HTTP.

Sur la base de cette hypothèse, en plus des octets du fichier, vous souhaitez également enregistrer le type MIME.

Comment trouver le type MIME d'un fichier? Je suis actuellement sur un Mac, mais cela devrait également fonctionner sur Windows.

Le navigateur ajoute-t-il ces informations lors de la publication du fichier sur la page Web?

Existe-t-il une bibliothèque python soignée pour trouver ces informations? Un WebService ou (encore mieux) une base de données téléchargeable?

Daren Thomas
la source

Réponses:

218

La méthode python-magic suggérée par toivotuo est obsolète. Le tronc actuel de Python-magic est sur Github et basé sur le readme là-bas, trouver le type MIME se fait comme ceci.

# For MIME types
import magic
mime = magic.Magic(mime=True)
mime.from_file("testdata/test.pdf") # 'application/pdf'
Simon Zimmermann
la source
17
Merci pour le commentaire! veuillez noter que "au-dessus" est un concept difficile dans stackoverflow, car l'ordre est groupé par votes et ordonné aléatoirement à l'intérieur des groupes. Je suppose que vous vous référez à la réponse de @ toivotuo.
Daren Thomas
1
Ouais, je n’avais pas assez de "points" pour créer des commentaires au moment de la rédaction de cette réponse. Mais j'aurais probablement dû l'écrire en commentaire, pour que le @toivotuo puisse éditer sa question.
Simon Zimmermann
1
rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL: darwinsys.com/file Résumé: liaisons Python pour l'API libmagic rpm -qf / usr / bin / file -i Nom: fichier URL: darwinsys.com/file python-magic de darwinsys.com/file et fourni avec Linux Fedora fonctionne comme le dit @ toivotuo. Et semble plus courant.
Sérgio
7
Attention, le package debian / ubuntu appelé python-magic est différent du package pip du même nom. Les deux sont import magicmais ont un contenu incompatible. Voir stackoverflow.com/a/16203777/3189 pour en savoir plus.
Hamish Downer
1
Comme je l'ai commenté sur la réponse de toivotuo, elle n'est pas obsolète! Vous parlez d'une bibliothèque différente. Pouvez-vous supprimer ou remplacer cette affirmation dans votre réponse? Il est actuellement très difficile de trouver la meilleure solution.
bodo
87

Le module mimetypes de la bibliothèque standard déterminera / devinera le type MIME à partir d'une extension de fichier.

Si les utilisateurs téléchargent des fichiers, la publication HTTP contiendra le type MIME du fichier à côté des données. Par exemple, Django rend ces données disponibles en tant qu'attribut de l' objet UploadedFile .

Dave Webb
la source
12
Si les fichiers sont stockés dans des BLOB, comme spécifié dans la question, vous ne connaissez peut-être pas l'extension de fichier.
Escargot mécanique
55
Les extensions de fichier ne sont pas un moyen fiable de déterminer le type mime.
Cerin
13
import mimetypes mimetypes.MimeTypes().guess_type(filename)[0]
Jonathan
4
en python 3.6 cela fonctionne:mimetypes.guess_type(path_file_to_upload)[1]
JinSnow
3
Bien que @cerin ait raison de dire que les extensions de fichiers ne sont pas fiables, je viens de découvrir que la précision de python-magic(comme suggéré dans la réponse du haut) est encore plus faible, comme le confirme github.com/s3tools/s3cmd/issues/198 . Donc, mimetypessemble un meilleur candidat pour moi.
danqing
46

Un moyen plus fiable que d'utiliser la bibliothèque mimetypes serait d'utiliser le paquet python-magic.

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

Cela équivaudrait à utiliser file (1).

Sur Django, on peut également s'assurer que le type MIME correspond à celui de UploadedFile.content_type.

toivotuo
la source
2
Voir l'article de Simon Zimmermann pour une mise à jour de l'utilisation de python-magic
Daren Thomas
@DarenThomas: Comme mentionné dans la réponse de mammadori, cette réponse n'est pas dépassée et distincte de la solution de Simon Zimmermann. Si vous avez installé l'utilitaire de fichiers, vous pouvez probablement utiliser cette solution. Cela fonctionne pour moi avec file-5.32. Sur gentoo, vous devez également activer l'indicateur USE python pour le package de fichiers.
bodo
36

Cela semble être très facile

>>> 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)

Veuillez vous référer à Old Post

Mise à jour - Selon le commentaire @Garrets, dans python 3, c'est plus simple:

import mimetypes
print(mimetypes.guess_type("sample.html"))
Laxmikant Ratnaparkhi
la source
4
Je ne pense pas que l'urllib soit nécessaire dans votre exemple.
BrotherJack
5
pour Python 3.X, remplacez import urllib par from urllib import request. Et puis utilisez "request" au lieu de urllib
Arjun Thakur
1
Fonctionne également pour python 2.7
Jay Modi
La solution de @ oetzi utilise ce module, mais est plus simple.
Garrett
11

Il existe 3 bibliothèques différentes qui encapsulent libmagic.

2 d'entre eux sont disponibles sur pypi (donc l'installation de pip fonctionnera):

  • filemagic
  • python-magie

Et un autre, similaire à python-magic est disponible directement dans les dernières sources libmagic, et c'est probablement celui que vous avez probablement dans votre distribution Linux.

Dans Debian, le paquet python-magic concerne celui-ci et il est utilisé comme toivotuo l'a dit et il n'est pas obsolète comme l'a dit Simon Zimmermann (IMHO).

Il me semble une autre prise (par l'auteur original de libmagic).

Dommage n'est pas disponible directement sur pypi.

mammadori
la source
J'ai ajouté un dépôt pour plus de commodité: github.com/mammadori/magic-python de cette façon, vous pouvez: pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
mammadori
10

en python 2.6:

mime = subprocess.Popen("/usr/bin/file --mime PATH", shell=True, \
    stdout=subprocess.PIPE).communicate()[0]
apito
la source
6
Ceci n'est pas nécessaire, car la filecommande n'est en fait qu'un wrapper autour de libmagic. Vous pouvez aussi bien utiliser la liaison python (python-magic), comme dans la réponse de Simon.
Escargot mécanique
6
Cela dépend du système d'exploitation. Sur Mac OS X, par exemple, vous avez "file" mais pas libmagic dans l'environnement normal.
rptb1
9

Mise à jour 2017

Pas besoin d'aller sur github, il est sur PyPi sous un autre nom:

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

Le code peut également être simplifié:

>>> import magic

>>> magic.from_file('/tmp/img_3304.jpg', mime=True)
'image/jpeg'
Gringo Suave
la source
pouvez-vous faire la même chose pour le fichier js ou css?
kumbhanibhavesh
Bien sûr, pourquoi pas??
Gringo Suave
9

Liaisons Python avec libmagic

Toutes les différentes réponses sur ce sujet sont très déroutantes, j'espère donc donner un peu plus de clarté avec cet aperçu des différentes liaisons de libmagic. Auparavant, mammadori a donné une brève réponse énumérant l'option disponible.

libmagic

Lors de la détermination d'un fichier de type mime, l'outil de choix est simplement appelé fileet son back-end est appelé libmagic. (Voir la page d'accueil du projet .) Le projet est développé dans un référentiel cvs privé, mais il existe un miroir git en lecture seule sur github .

Maintenant, cet outil, dont vous aurez besoin si vous souhaitez utiliser l'une des liaisons libmagic avec python, est déjà livré avec ses propres liaisons python appelées file-magic. Il n'y a pas beaucoup de documentation dédié pour eux, mais vous pouvez toujours jeter un oeil à la page de manuel de la bibliothèque C: man libmagic. L'utilisation de base est décrite dans le fichier readme :

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)

En dehors de cela, vous pouvez également utiliser la bibliothèque en créant un Magicobjet en utilisant magic.open(flags)comme indiqué dans le fichier d'exemple .

Les deux toivotuo et l' utilisation ewr2san ces file-magicfixations incluses dans l' fileoutil. Ils supposent à tort qu'ils utilisent le python-magicpackage. Cela semble indiquer que si les deux fileet python-magicsont installés, le module python se magicréfère à l'ancien.

python-magie

C'est la bibliothèque dont parle Simon Zimmermann dans sa réponse et qui est également employée par Claude COULOMBE ainsi que Gringo Suave .

filemagic

Remarque : ce projet a été mis à jour pour la dernière fois en 2013!

En raison du fait qu'elle est basée sur le même c-api, cette bibliothèque présente une certaine similitude avec l' file-magicinclusion dans libmagic. Il n'est mentionné que par mammadori et aucune autre réponse ne l'emploie.

Bodo
la source
7

La méthode de @toivotuo a fonctionné le mieux et la plus fiable pour moi sous python3. Mon objectif était d'identifier les fichiers gzippés qui n'ont pas d'extension .gz fiable. J'ai installé python3-magic.

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))

pour un fichier gzip, il renvoie: application / gzip; charset = binaire

pour un fichier txt décompressé (données iostat): text / plain; charset = us-ascii

pour un fichier tar: application / x-tar; charset = binaire

pour un fichier bz2: application / x-bzip2; charset = binaire

et enfin et surtout pour moi un fichier .zip: application / zip; charset = binaire

ewr2san
la source
7

python 3 réf: https://docs.python.org/3.2/library/mimetypes.html

mimetypes.guess_type (url, strict = True) Devinez le type d'un fichier en fonction de son nom de fichier ou de son URL, donné par url. La valeur de retour est un tuple (type, encodage) où type est None si le type ne peut pas être deviné (suffixe manquant ou inconnu) ou une chaîne de la forme 'type / sous-type', utilisable pour un en-tête de type de contenu MIME.

encoding est None pour aucun encodage ou le nom du programme utilisé pour encoder (par exemple compress ou gzip). Le codage peut être utilisé comme en-tête Content-Encoding, et non comme en-tête Content-Transfer-Encoding. Les mappages sont basés sur des tables. Les suffixes de codage sont sensibles à la casse; les suffixes de type sont d'abord essayés avec sensibilité à la casse, puis sans sensibilité à la casse.

L'argument strict facultatif est un indicateur spécifiant si la liste des types MIME connus est limitée aux seuls types officiels enregistrés auprès de l'IANA. Lorsque strict vaut True (valeur par défaut), seuls les types IANA sont pris en charge; lorsque strict vaut False, certains types MIME supplémentaires non standard mais couramment utilisés sont également reconnus.

import mimetypes
print(mimetypes.guess_type("sample.html"))
oetzi
la source
6

Vous n'avez pas indiqué quel serveur Web vous utilisiez, mais Apache a un joli petit module appelé Mime Magic qu'il utilise pour déterminer le type d'un fichier lorsqu'on lui demande de le faire. Il lit une partie du contenu du fichier et essaie de déterminer de quel type il s'agit en fonction des caractères trouvés. Et comme Dave Webb l'a mentionné, le module MimeTypes sous python fonctionnera, à condition qu'une extension soit pratique.

Sinon, si vous êtes assis sur une boîte UNIX, vous pouvez utiliser sys.popen('file -i ' + fileName, mode='r')pour saisir le type MIME. Windows devrait avoir une commande équivalente, mais je ne suis pas sûr de ce que c'est.

akdom
la source
7
De nos jours, vous pouvez simplement faire subprocess.check_output (['file', '-b', '--mime', filename])
Nathan Villaescusa
Il n'y a vraiment aucune raison de recourir à un outil externe lorsque python-magic fait l'équivalent, le tout enveloppé et confortable.
damd
4

En Python 3.x et webapp avec l'URL du fichier qui ne peut pas avoir d'extension ou de fausse extension. Vous devez installer python-magic, en utilisant

pip3 install python-magic

Pour Mac OS X, vous devez également installer libmagic en utilisant

brew install libmagic

Extrait de code

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)

Sinon, vous pouvez mettre une taille dans la lecture

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
la source
Sera-ce charger le fichier entier?
吴毅 凡
Non, c'est un flux, donc normalement quelques octets.
Claude COULOMBE
J'ai édité par response.readline () ou response.read (128) Merci!
Claude COULOMBE
3

J'essaye d'abord la bibliothèque de types mimetypes. Si cela ne fonctionne pas, j'utilise la librairie python-magic à la place.

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
la source
1

Le module mimetypes reconnaît simplement un type de fichier basé sur l'extension de fichier. Si vous essayez de récupérer un type de fichier d'un fichier sans extension, les types MIME ne fonctionneront pas.

Helder
la source
3
Je ne pense pas que ce soit vrai. Le type MIME consiste à savoir comment informer les autres sur un format de données, et non à découvrir le format de données vous-même. Si vous utilisez un outil qui devine le format uniquement en fonction de l'extension et imprime les types MIME, vous ne pouvez pas utiliser cet outil s'il n'y a pas d'extensions de fichier. Mais d'autres moyens de deviner le format sont également possibles, par exemple en vérifiant avec un analyseur.
erikbwork
1

Je suis surpris que personne ne l'ait mentionné, mais Pygments est capable de faire une supposition éclairée sur le type mime, en particulier, des documents texte.

Pygments est en fait une bibliothèque de coloration syntaxique Python, mais possède une méthode qui permet de deviner de manière éclairée le type de document pris en charge sur 500 de votre document. ie 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)

Production:

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

Maintenant, ce n'est pas parfait, mais si vous avez besoin de savoir lequel des 500 formats de document est utilisé, c'est sacrément utile.

Eric McLachlan
la source
0

J'ai essayé beaucoup d 'exemples mais avec Django, mutagen joue bien.

Exemple de vérification si les fichiers sont mp3

from mutagen.mp3 import MP3, HeaderNotFoundError  

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

L'inconvénient est que votre capacité à vérifier les types de fichiers est limitée, mais c'est un excellent moyen si vous souhaitez non seulement vérifier le type de fichier, mais également accéder à des informations supplémentaires.

Artem Bernatskyi
la source
Je dois aussi vérifier la sécurité
Artem Bernatskyi
0

Pour les données de type byte Array, vous pouvez utiliser magic.from_buffer (_byte_array, mime = True)

Super-utilisateur
la source
-1

vous pouvez utiliser le module imghdr Python.

jianpx
la source
1
Ce n'est pas un commentaire utile, car il ne donne pas d'exemples ni ne dit vraiment comment ou pourquoi imghdr aiderait ici.
erikbwork
2
Oui, je comprends cela. Il y a plus d'un an, mais peut-être que vous pouvez toujours la mettre à jour car il y a encore des gens qui recherchent cette question, comme moi. Si vous avez besoin d'aide, vous pouvez me le dire.
erikbwork
1
Cela ne fonctionne que pour une liste très limitée de types d'images. Il n'a aucune idée des fichiers texte, des archives compressées, des formats de documents, etc.
tripleee