¿Cómo encontrar el tipo MIME de un archivo en Python?

194

Supongamos que desea guardar un montón de archivos en algún lugar, por ejemplo, en BLOB. Supongamos que desea distribuir estos archivos a través de una página web y que el cliente abra automáticamente la aplicación / visor correcto.

Suposición: el navegador determina qué aplicación / visor debe usar el encabezado mime-type (content-type?) En la respuesta HTTP.

Según esa suposición, además de los bytes del archivo, también desea guardar el tipo MIME.

¿Cómo encontrarías el tipo MIME de un archivo? Actualmente estoy en una Mac, pero esto también debería funcionar en Windows.

¿El navegador agrega esta información cuando publica el archivo en la página web?

¿Hay una biblioteca de Python ordenada para encontrar esta información? ¿Un servicio web o (aún mejor) una base de datos descargable?

Daren Thomas
fuente

Respuestas:

218

El método python-magic sugerido por toivotuo está desactualizado. El tronco actual de Python-magic está en Github y, según el archivo Léame allí, encontrar el tipo MIME se hace así.

# For MIME types
import magic
mime = magic.Magic(mime=True)
mime.from_file("testdata/test.pdf") # 'application/pdf'
Simon Zimmermann
fuente
17
¡gracias por el comentario! tenga en cuenta que "arriba" es un concepto difícil en stackoverflow, ya que el orden se agrupa por votos y se ordena al azar dentro de los grupos. Supongo que se refieren a la respuesta de @ toivotuo.
Daren Thomas
1
Sí, no tenía suficientes "puntos" para crear comentarios al momento de escribir esta respuesta. Pero probablemente debería haberlo escrito como un comentario, para que @toivotuo pudiera haber editado su pregunta.
Simon Zimmermann
1
rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL: darwinsys.com/file Resumen: enlaces de Python para la API de libmagic rpm -qf / usr / bin / file -i Nombre: archivo URL: darwinsys.com/file python-magic de darwinsys.com/file y que viene con Linux Fedora funciona como dijo @ toivotuo. Y parece más corriente principal.
Sérgio
77
Tenga en cuenta que el paquete debian / ubuntu llamado python-magic es diferente al paquete pip del mismo nombre. Ambos son import magicpero tienen contenidos incompatibles. Consulte stackoverflow.com/a/16203777/3189 para obtener más información.
Hamish Downer
1
Como comenté en la respuesta de toivotuo, ¡no está desactualizada! Estás hablando de una biblioteca diferente. ¿Puedes por favor eliminar o reemplazar esa declaración en tu respuesta? Actualmente hace que encontrar la mejor solución sea realmente difícil.
bodo
86

El módulo mimetypes en la biblioteca estándar determinará / adivinará el tipo MIME a partir de una extensión de archivo.

Si los usuarios están cargando archivos, la publicación HTTP contendrá el tipo MIME del archivo junto con los datos. Por ejemplo, Django hace que estos datos estén disponibles como un atributo del objeto UploadedFile .

Dave Webb
fuente
12
Si los archivos se almacenan en BLOB, como se especifica en la pregunta, es posible que no conozca la extensión del archivo.
Caracol mecánico
55
Las extensiones de archivo no son una forma confiable de determinar el tipo mime.
Cerin
12
import mimetypes mimetypes.MimeTypes().guess_type(filename)[0]
Jonathan
44
en Python 3.6 esto funciona:mimetypes.guess_type(path_file_to_upload)[1]
JinSnow
3
Si bien @cerin tiene razón en que las extensiones de archivo no son confiables, acabo de descubrir que la precisión de python-magic(como se sugiere en la respuesta superior) es aún menor, según lo confirmado por github.com/s3tools/s3cmd/issues/198 . Entonces, mimetypesparece un mejor candidato para mí.
danqing
46

Una forma más confiable de usar la biblioteca de tipos de mime sería utilizar el paquete python-magic.

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

Esto sería equivalente a usar el archivo (1).

En Django también se puede asegurar que el tipo MIME coincida con el de UploadedFile.content_type.

toivotuo
fuente
2
Vea la publicación de Simon Zimmermann para un uso actualizado de python-magic
Daren Thomas
@DarenThomas: Como se menciona en la respuesta de mammadori, esta respuesta no está desactualizada y es distinta de la solución de Simon Zimmermann. Si tiene instalada la utilidad de archivos, probablemente pueda usar esta solución. A mí me funciona con el archivo 5.32. En gentoo también debe tener habilitado el indicador USE de python para el paquete de archivos.
bodo
35

Esto parece ser muy fácil.

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

Por favor, consulte la publicación anterior

Actualización : según el comentario de @Garrets, en python 3 es más simple:

import mimetypes
print(mimetypes.guess_type("sample.html"))
Laxmikant Ratnaparkhi
fuente
44
No creo que se requiera la urllib en su ejemplo.
BrotherJack
55
para Python 3.X reemplace import urllib con la solicitud de importación urllib. Y luego use "request" en lugar de urllib
Arjun Thakur
1
Funciona también para python 2.7
Jay Modi
La solución de @ oetzi utiliza este módulo, pero es más simple.
Garrett
11

Hay 3 bibliotecas diferentes que envuelven libmagic.

2 de ellos están disponibles en pypi (por lo que la instalación de pip funcionará):

  • filemagic
  • pitón-magia

Y otro, similar a python-magic, está disponible directamente en las últimas fuentes de libmagic, y es el que probablemente tenga en su distribución de Linux.

En Debian, el paquete python-magic es sobre este y se usa como dijo toivotuo y no está obsoleto como dijo Simon Zimmermann (en mi humilde opinión).

Me parece otra toma (por el autor original de libmagic).

Lástima que no esté disponible directamente en pypi.

mammadori
fuente
Agregué un repositorio para mayor comodidad: github.com/mammadori/magic-python de esa manera puedes: 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
fuente
66
Esto es innecesario, ya que el filecomando es básicamente un contenedor de libmagic. También puede usar el enlace de python (python-magic), como en la respuesta de Simon.
Caracol mecánico
66
Eso depende del sistema operativo. En Mac OS X, por ejemplo, tiene "archivo" pero no libmagic en el entorno normal.
rptb1
9

Actualización 2017

No es necesario ir a github, está en PyPi con un nombre diferente:

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

El código también se puede simplificar:

>>> import magic

>>> magic.from_file('/tmp/img_3304.jpg', mime=True)
'image/jpeg'
Gringo Suave
fuente
¿Puedes hacer lo mismo para js o css file?
kumbhanibhavesh
¿¿Seguro Por qué no??
Gringo Suave
9

Enlaces de Python a libmagic

Todas las diferentes respuestas sobre este tema son muy confusas, por lo que espero dar un poco más de claridad con esta descripción general de los diferentes enlaces de libmagic. Anteriormente, mammadori dio una respuesta breve que enumeraba la opción disponible.

libmagic

Al determinar un tipo de archivos MIME, la herramienta de elección simplemente se llama filey se llama a su back-end libmagic. (Consulte la página de inicio del Proyecto ). El proyecto se desarrolla en un repositorio privado cvs, pero hay un espejo git de solo lectura en github .

Ahora esta herramienta, que necesitará si desea utilizar cualquiera de los enlaces de libmagic con python, ya viene con sus propios enlaces de python llamados file-magic. No hay mucha documentación específica para ellos, pero siempre se puede echar un vistazo a la página del manual de la biblioteca C: man libmagic. El uso básico se describe en el archivo Léame :

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)

Además de esto, también puede usar la biblioteca creando un Magicobjeto usando magic.open(flags)como se muestra en el archivo de ejemplo .

Tanto toivotuo como ewr2san usan estos file-magicenlaces incluidos en la fileherramienta. Asumen erróneamente que están usando el python-magicpaquete. Esto parece indicar, que si ambos filey python-magicestán instalados, el módulo de Python magicse refiere a la anterior.

pitón-magia

Esta es la biblioteca de la que Simon Zimmermann habla en su respuesta y que también es empleada por Claude COULOMBE y Gringo Suave .

filemagic

Nota : ¡Este proyecto se actualizó por última vez en 2013!

Debido a que se basa en la misma c-api, esta biblioteca tiene cierta similitud con la file-magicincluida en libmagic. Mammadori solo lo menciona y ninguna otra respuesta lo emplea.

bodo
fuente
7

El método de @toivotuo funcionó mejor y más confiable para mí en python3. Mi objetivo era identificar los archivos comprimidos que no tienen una extensión .gz confiable. Instalé 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))

para un archivo comprimido devuelve: application / gzip; juego de caracteres = binario

para un archivo txt descomprimido (datos de iostat): text / plain; charset = us-ascii

para un archivo tar: application / x-tar; juego de caracteres = binario

para un archivo bz2: application / x-bzip2; juego de caracteres = binario

y por último, pero no menos importante para mí, un archivo .zip: application / zip; juego de caracteres = binario

ewr2san
fuente
7

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

mimetypes.guess_type (url, strictly = True) Adivina el tipo de archivo basado en su nombre de archivo o URL, dado por url. El valor de retorno es una tupla (tipo, codificación) donde el tipo es Ninguno si el tipo no se puede adivinar (sufijo perdido o desconocido) o una cadena de la forma 'tipo / subtipo', utilizable para un encabezado de tipo de contenido MIME.

encoding es None para ninguna codificación o el nombre del programa utilizado para codificar (por ejemplo, comprimir o gzip). La codificación es adecuada para su uso como encabezado de codificación de contenido, no como encabezado de codificación de transferencia de contenido. Las asignaciones son manejadas por tablas. Los sufijos de codificación distinguen entre mayúsculas y minúsculas; los sufijos de tipo se prueban primero con mayúsculas y minúsculas, luego con mayúsculas y minúsculas.

El argumento estricto opcional es una bandera que especifica si la lista de tipos MIME conocidos se limita solo a los tipos oficiales registrados con IANA. Cuando estricto es verdadero (el valor predeterminado), solo se admiten los tipos de IANA; cuando estricto es Falso, también se reconocen algunos tipos MIME adicionales no estándar pero comúnmente utilizados.

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

No indicó qué servidor web estaba utilizando, pero Apache tiene un pequeño y agradable módulo llamado Mime Magic que utiliza para determinar el tipo de archivo cuando se le indica que lo haga. Lee parte del contenido del archivo e intenta averiguar qué tipo se basa en los caracteres encontrados. Y como Dave Webb mencionó, el módulo MimeTypes en Python funcionará, siempre que una extensión sea útil.

Alternativamente, si está sentado en un cuadro de UNIX, puede usar sys.popen('file -i ' + fileName, mode='r')para tomar el tipo MIME. Windows debería tener un comando equivalente, pero no estoy seguro de qué es.

akdom
fuente
77
Hoy en día solo puede hacer subprocess.check_output (['' file ',' -b ',' --mime ', filename])
Nathan Villaescusa
Realmente no hay razón para recurrir al uso de una herramienta externa cuando python-magic hace lo mismo, todo envuelto y acogedor.
maldito
4

En Python 3.xy webapp con url al archivo que no podía tener una extensión o una extensión falsa. Debes instalar python-magic, usando

pip3 install python-magic

Para Mac OS X, también debe instalar libmagic usando

brew install libmagic

Fragmento de código

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)

alternativamente, podría poner un tamaño en la lectura

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
fuente
¿Se cargará todo el archivo?
吴毅 凡
No, es una secuencia, por lo que normalmente solo unos pocos bytes.
Claude COULOMBE
He editado por response.readline () o response.read (128) ¡Gracias!
Claude COULOMBE
3

Intento primero la biblioteca mimetypes. Si no funciona, utilizo la biblioteca python-magic en su lugar.

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
fuente
1

El módulo mimetypes solo reconoce un tipo de archivo basado en la extensión del archivo. Si intenta recuperar un tipo de archivo sin extensión, los tipos mime no funcionarán.

Helder
fuente
3
No creo que sea verdad. El tipo MIME trata sobre cómo contarles a otros sobre un formato de datos, no sobre cómo averiguar el formato de datos usted mismo. Si usa una herramienta que adivina el formato solo en función de la extensión e imprime los tipos MIME, entonces no puede usar esa herramienta si no hay extensiones de archivo. Pero también son posibles otras formas de adivinar el formato, por ejemplo, comprobando con un analizador sintáctico.
erikbwork
1

Me sorprende que nadie lo haya mencionado, pero Pygments es capaz de hacer una conjetura sobre el tipo de mimo de, en particular, los documentos de texto.

Pygments es en realidad una biblioteca de resaltado de sintaxis de Python, pero tiene un método que hará una suposición educada sobre cuál de los 500 tipos de documentos admitidos es su documento. es decir, 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)

Salida:

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

Ahora, no es perfecto, pero si necesita saber cuál de los 500 formatos de documentos se están utilizando, esto es bastante útil.

Eric McLachlan
fuente
0

He probado muchos ejemplos, pero con Django mutagen funciona muy bien.

Ejemplo de comprobación de si los archivos son mp3

from mutagen.mp3 import MP3, HeaderNotFoundError  

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

La desventaja es que su capacidad para verificar los tipos de archivos es limitada, pero es una excelente manera si no solo desea verificar el tipo de archivo sino también acceder a información adicional.

Artem Bernatskyi
fuente
Necesito verificar la seguridad también
Artem Bernatskyi
0

Para los datos de tipo de matriz de bytes, puede usar magic.from_buffer (_byte_array, mime = True)

Superusuario
fuente
-1

puedes usar el módulo imghdr Python.

jianpx
fuente
1
Este no es un comentario útil, porque no da ejemplos ni realmente dice cómo o por qué imghdr ayudaría aquí.
erikbwork
2
Sí, lo entiendo. Hace más de un año, pero tal vez aún pueda actualizarlo porque todavía hay personas que buscan esta pregunta, como yo. Si necesitas ayuda, puedes decirme.
erikbwork
1
Solo funciona para una lista muy limitada de tipos de imágenes. No tiene idea sobre archivos de texto, archivos comprimidos, formatos de documentos, etc.
tripleee