Come trovare il tipo mime di un file in Python?


194

Supponiamo che tu voglia salvare un mucchio di file da qualche parte, ad esempio in BLOB. Supponiamo che tu voglia trasferire questi file tramite una pagina Web e fare in modo che il client apra automaticamente l'applicazione / il visualizzatore corretti.

Presupposto: il browser rileva quale applicazione / visualizzatore utilizzare dall'intestazione mime-type (content-type?) Nella risposta HTTP.

Sulla base di tale presupposto, oltre ai byte del file, si desidera salvare anche il tipo MIME.

Come troveresti il ​​tipo MIME di un file? Sono attualmente su un Mac, ma questo dovrebbe funzionare anche su Windows.

Il browser aggiunge queste informazioni quando pubblica il file nella pagina Web?

Esiste una libreria Python ordinata per trovare queste informazioni? Un servizio Web o (ancora meglio) un database scaricabile?

Risposte:


218

Il metodo magico-pitone suggerito da toivotuo è obsoleto. L' attuale trunk di Python-magic è su Github e basato sul readme lì, che trova il tipo MIME, viene fatto in questo modo.

# For MIME types
import magic
mime = magic.Magic(mime=True)
mime.from_file("testdata/test.pdf") # 'application/pdf'

17
grazie per il commento! si noti che "sopra" è un concetto difficile nello stackoverflow, poiché l'ordinamento è raggruppato per voti e ordinato in modo casuale all'interno dei gruppi. Immagino che ti riferisci alla risposta di @ toivotuo.
Daren Thomas,

1
Sì, non avevo abbastanza "punti" per creare commenti al momento della stesura di questa risposta. Ma probabilmente avrei dovuto scriverlo come commento, in modo che @toivotuo avrebbe potuto modificare la sua domanda.
Simon Zimmermann,

1
rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL: darwinsys.com/file Riepilogo: collegamenti Python per l'API libmagic rpm -qf / usr / bin / file -i Nome: file URL: darwinsys.com/file python-magic da darwinsys.com/file e che viene fornito con Linux Fedora funziona come ha detto @ toivotuo. E sembra più flusso principale.
Sérgio,

7
Attenzione che il pacchetto debian / ubuntu chiamato python-magic è diverso dal pacchetto pip con lo stesso nome. Entrambi sono import magicma hanno contenuti incompatibili. Vedi stackoverflow.com/a/16203777/3189 per ulteriori informazioni.
Hamish Downer,

1
Come ho commentato la risposta di toivotuo, non è obsoleta! Stai parlando di una biblioteca diversa. Potete per favore rimuovere o sostituire quella dichiarazione nella vostra risposta? Attualmente rende davvero difficile trovare la soluzione migliore.
bodo,

87

Il modulo mimetypes nella libreria standard determinerà / indovinerà il tipo MIME da un'estensione di file.

Se gli utenti caricano file, il post HTTP conterrà il tipo MIME del file accanto ai dati. Ad esempio, Django rende disponibili questi dati come attributo dell'oggetto UploadedFile .


12
Se i file sono archiviati in BLOB, come specificato nella domanda, è possibile che non si conosca l'estensione del file.
Lumaca meccanica

55
Le estensioni dei file non sono un modo affidabile per determinare il tipo mime.
Cerin,

13
import mimetypes mimetypes.MimeTypes().guess_type(filename)[0]
Jonathan,

4
in Python 3.6 funziona:mimetypes.guess_type(path_file_to_upload)[1]
JinSnow

3
Mentre @cerin ha ragione sul fatto che le estensioni dei file non sono affidabili, ho appena scoperto che l'accuratezza di python-magic(come suggerito nella risposta in alto) è ancora inferiore, come confermato da github.com/s3tools/s3cmd/issues/198 . Quindi, mimetypessembra un candidato migliore per me.
danqing,

46

Un modo più affidabile rispetto all'utilizzo della libreria mimetypes sarebbe utilizzare il pacchetto python-magic.

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

Ciò equivarrebbe ad usare il file (1).

Su Django si potrebbe anche assicurarsi che il tipo MIME corrisponda a quello di UploadedFile.content_type.


2
Vedi il post di Simon Zimmermann per un uso aggiornato di python-magic
Daren Thomas,

@DarenThomas: Come menzionato nella risposta di mammadori, questa risposta non è obsoleta e distinta dalla soluzione di Simon Zimmermann. Se hai installato l'utilità di file, puoi probabilmente usare questa soluzione. Funziona per me con il file 5.32. Su gentoo devi anche avere il flag USE python abilitato per il pacchetto di file.
bodo,

36

Questo sembra essere molto semplice

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

Per favore, riferisci Old Post

Aggiornamento - Secondo il commento di @Garrets, in python 3 è più semplice:

import mimetypes
print(mimetypes.guess_type("sample.html"))

4
Non credo che l'urllib sia richiesto nel tuo esempio.
BrotherJack,

5
per Python 3.X sostituire import urllib con dalla richiesta di importazione urllib. E poi usa "richiesta" invece di urllib
Arjun Thakur il

1
Funziona anche con Python 2.7
Jay Modi,

La soluzione di @ oetzi utilizza questo modulo, ma è più semplice.
Garrett,

11

Ci sono 3 diverse librerie che avvolgono libmagic.

2 di questi sono disponibili su pypi (quindi l'installazione pip funzionerà):

  • filemagic
  • python-magic

E un altro, simile a Python-Magic, è disponibile direttamente nelle ultime fonti libmagic, ed è quello che probabilmente hai nella tua distribuzione Linux.

In Debian il pacchetto python-magic parla di questo ed è usato come detto toivotuo e non è obsoleto come diceva Simon Zimmermann (IMHO).

Mi sembra un'altra interpretazione (dall'autore originale di libmagic).

Peccato che non sia disponibile direttamente su Pypi.


Ho aggiunto un repository per comodità: github.com/mammadori/magic-python in questo modo è possibile: pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
mammadori,

10

in Python 2.6:

mime = subprocess.Popen("/usr/bin/file --mime PATH", shell=True, \
    stdout=subprocess.PIPE).communicate()[0]

6
Questo non è necessario, poiché il filecomando è fondamentalmente solo un wrapper per libmagic. Puoi anche usare il binding python (python-magic), come nella risposta di Simon.
Lumaca meccanica

6
Dipende dal sistema operativo. Su Mac OS X, ad esempio, hai "file" ma non libmagic nell'ambiente normale.
rptb1,

9

Aggiornamento 2017

Non c'è bisogno di andare su github, è su PyPi con un nome diverso:

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

Anche il codice può essere semplificato:

>>> import magic

>>> magic.from_file('/tmp/img_3304.jpg', mime=True)
'image/jpeg'

puoi fare lo stesso per il file js o css?
kumbhanibhavesh,

Certo, perché no??
Gringo Suave,

9

Python si lega a libmagic

Tutte le diverse risposte su questo argomento sono molto confuse, quindi spero di dare un po 'più di chiarezza con questa panoramica delle diverse associazioni di libmagic. Precedentemente mammadori ha dato una breve risposta elencando l'opzione disponibile.

libmagic

Quando si determina un tipo mime di file, lo strumento preferito viene semplicemente chiamato filee viene chiamato il suo back-end libmagic. (Vedi la home page del Progetto .) Il progetto è sviluppato in un repository cvs privato, ma c'è un mirror git di sola lettura su github .

Ora questo strumento, che ti servirà se vuoi usare una qualsiasi delle associazioni libmagiche con Python, viene già fornito con le sue stesse associazioni Python chiamate file-magic. Non c'è molto di documentazione dedicato per loro, ma si può sempre avere uno sguardo alla pagina man del c-library: man libmagic. L'utilizzo di base è descritto nel file Leggimi :

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)

Oltre a questo, puoi anche usare la libreria creando un Magicoggetto usando magic.open(flags)come mostrato nel file di esempio .

Sia toivotuo e l'uso ewr2san questi file-magicattacchi inclusi nel filestrumento. Presumono erroneamente che stanno usando il python-magicpacchetto. Questo sembra indicare che se entrambi filee python-magicsono installati, il modulo python si magicriferisce a quello precedente.

python-magic

Questa è la biblioteca di cui Simon Zimmermann parla nella sua risposta e che è anche impiegato da Claude COULOMBE e da Gringo Suave .

filemagic

Nota : questo progetto è stato aggiornato l'ultima volta nel 2013!

Essendo basato sullo stesso c-api, questa libreria ha alcune somiglianze con file-magicincluso in libmagic. Viene menzionato solo da mammadori e nessun'altra risposta lo utilizza.


7

Il metodo di @toivotuo ha funzionato meglio e in modo più affidabile per me con Python3. Il mio obiettivo era quello di identificare i file compressi con gzip che non hanno un'estensione affidabile .gz. Ho installato 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))

per un file gzipped restituisce: application / gzip; charset = binario

per un file txt decompresso (dati iostat): text / plain; charset = us-ascii

per un file tar: application / x-tar; charset = binario

per un file bz2: application / x-bzip2; charset = binario

e ultimo ma non meno importante per me un file .zip: application / zip; charset = binario


7

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

mimetypes.guess_type (url, strict = True) Indovina il tipo di un file in base al suo nome file o URL, fornito da url. Il valore restituito è una tupla (tipo, codifica) in cui il tipo è Nessuno se il tipo non può essere indovinato (suffisso mancante o sconosciuto) o una stringa della forma "tipo / sottotipo", utilizzabile per un'intestazione del tipo di contenuto MIME.

la codifica è Nessuna per nessuna codifica o il nome del programma utilizzato per codificare (ad esempio compress o gzip). La codifica è adatta per l'uso come intestazione Content-Encoding, non come intestazione Content-Transfer-Encoding. I mapping sono guidati da tabella. I suffissi di codifica fanno distinzione tra maiuscole e minuscole; i suffissi di tipo vengono prima provati in modo sensibile a maiuscole e minuscole, poi senza maiuscole e minuscole.

L'argomento rigoroso facoltativo è una bandiera che specifica se l'elenco di tipi MIME noti è limitato ai soli tipi ufficiali registrati con IANA. Quando rigoroso è True (impostazione predefinita), sono supportati solo i tipi IANA; quando rigoroso è False, vengono riconosciuti anche alcuni tipi MIME aggiuntivi non standard ma comunemente utilizzati.

import mimetypes
print(mimetypes.guess_type("sample.html"))

6

Non hai indicato quale server web stavi utilizzando, ma Apache ha un bel modulo chiamato Mime Magic che usa per determinare il tipo di file quando ti viene detto di farlo. Legge alcuni dei contenuti del file e cerca di capire quale tipo si basa sui caratteri trovati. E come Dave Webb ha menzionato il modulo MimeTypes sotto python funzionerà, a condizione che un'estensione sia utile.

In alternativa, se sei seduto su una scatola UNIX puoi usare sys.popen('file -i ' + fileName, mode='r')per afferrare il tipo MIME. Windows dovrebbe avere un comando equivalente, ma non sono sicuro di cosa sia.


7
Al giorno d'oggi puoi semplicemente fare subprocess.check_output (['file', '-b', '--mime', nome file])
Nathan Villaescusa,

Non c'è davvero alcun motivo per ricorrere all'uso di uno strumento esterno quando python-magic fa la stessa cosa, tutto avvolto e accogliente.
maledetto

4

In Python 3.xe webapp con URL al file che non può avere un'estensione o un'estensione falsa. Dovresti installare python-magic, usando

pip3 install python-magic

Per Mac OS X, dovresti anche installare libmagic usando

brew install libmagic

Snippet di codice

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)

in alternativa puoi inserire una dimensione nella lettura

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)

Verrà caricato l'intero file?
吴毅 凡

No, è un flusso, quindi normalmente solo pochi byte.
Claude COULOMBE,

Ho modificato da response.readline () o response.read (128) Grazie!
Claude COULOMBE,

3

Provo prima la libreria dei mimetipi. Se non funziona, utilizzo invece libary python-magic.

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

1

Il modulo mimetypes riconosce solo un tipo di file basato sull'estensione del file. Se proverai a recuperare un tipo di file di un file senza estensione, i mimetipi non funzioneranno.


3
Non penso sia vero. Il tipo MIME riguarda come comunicare agli altri un formato di dati, non come scoprire da soli il formato dei dati. Se si utilizza uno strumento che indovina il formato solo in base all'estensione e stampa i tipi MIME, non è possibile utilizzare tale strumento se non sono presenti estensioni di file. Ma sono possibili anche altri modi per indovinare il formato, ad esempio controllando con un parser.
erikbwork,

1

Sono sorpreso che nessuno lo abbia menzionato tranne Pygments è in grado di fare un'ipotesi colta sul tipo mime, in particolare, dei documenti di testo.

Pygments è in realtà una libreria di evidenziazione della sintassi di Python ma ha un metodo che farà un'ipotesi mirata su quale dei 500 tipi di documenti supportati sia il tuo documento. cioè c ++ vs C # vs Python vs ecc

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)

Produzione:

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

Ora, non è perfetto, ma se devi essere in grado di dire quale dei 500 formati di documento vengono utilizzati, questo è davvero utile.


0

Ho provato molti esempi ma con Django il mutageno suona bene.

Esempio di verifica se i file sono mp3

from mutagen.mp3 import MP3, HeaderNotFoundError  

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

Il rovescio della medaglia è che la tua capacità di controllare i tipi di file è limitata, ma è un ottimo modo se vuoi non solo controllare il tipo di file ma anche accedere a informazioni aggiuntive.


Devo controllare anche la sicurezza
Artem Bernatskyi,


0

Per i dati di tipo array di byte è possibile utilizzare magic.from_buffer (_byte_array, mime = True)


-1

puoi usare il modulo imghdr Python.


1
Questo non è un commento utile, perché non fornisce esempi né dice in che modo o perché imghdr potrebbe aiutare qui.
erikbwork,

2
Sì, lo capisco. È passato più di un anno fa, ma forse puoi ancora aggiornarlo perché ci sono ancora persone che cercano questa domanda, come me. Se hai bisogno di aiuto, puoi dirmelo.
erikbwork,

1
Funziona solo per un elenco molto limitato di tipi di immagini. Non ha idea di file di testo, archivi compressi, formati di documenti, ecc.
tripleee
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.