Como encontrar o tipo mime de um arquivo em python?

193

Digamos que você queira salvar um monte de arquivos em algum lugar, por exemplo, em BLOBs. Digamos que você queira distribuir esses arquivos por meio de uma página da Web e fazer com que o cliente abra automaticamente o aplicativo / visualizador correto.

Suposição: O navegador descobre qual aplicativo / visualizador usar pelo cabeçalho mime-type (content-type?) Na resposta HTTP.

Com base nessa suposição, além dos bytes do arquivo, você também deseja salvar o tipo MIME.

Como você encontraria o tipo MIME de um arquivo? Atualmente, estou em um Mac, mas isso também deve funcionar no Windows.

O navegador adiciona essas informações ao postar o arquivo na página da web?

Existe uma biblioteca python pura para encontrar essas informações? Um WebService ou (melhor ainda) um banco de dados para download?

Daren Thomas
fonte

Respostas:

217

O método python-magic sugerido pelo toivotuo está desatualizado. O tronco atual do Python-magic está no Github e com base no leia-me lá, encontrando o tipo MIME, é feito assim.

# For MIME types
import magic
mime = magic.Magic(mime=True)
mime.from_file("testdata/test.pdf") # 'application/pdf'
Simon Zimmermann
fonte
17
obrigado pelo comentário! observe que "acima" é um conceito difícil no stackoverflow, pois a ordem é agrupada por votos e ordenada aleatoriamente dentro dos grupos. Acho que você se refere à resposta de @ toivotuo.
Daren Thomas
1
Sim, eu não tinha "pontos" suficientes para criar comentários no momento em que escrevi esta resposta. Mas eu provavelmente deveria ter escrito isso como um comentário, para que o @toivotuo pudesse ter editado sua pergunta.
Simon Zimmermann
1
rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL: darwinsys.com/file Resumo: Ligações Python para a API libmagic rpm -qf / usr / bin / file -i Nome: file URL: darwinsys.com/file python-magic em darwinsys.com/file e que vem com o Linux O Fedora funciona como o @ toivotuo's disse. E parece mais corrente principal.
Sérgio
7
Cuidado que o pacote debian / ubuntu chamado python-magic é diferente do pacote pip com o mesmo nome. Ambos têm import magicapenas conteúdo incompatível. Consulte stackoverflow.com/a/16203777/3189 para obter mais informações.
amigos estão dizendo sobre
1
Como eu comentei na resposta do toivotuo, ela não está desatualizada! Você está falando de uma biblioteca diferente. Você pode remover ou substituir essa declaração na sua resposta? Atualmente, é realmente difícil encontrar a melhor solução.
bodo
86

O módulo mimetypes na biblioteca padrão determina / adivinha o tipo MIME a partir de uma extensão de arquivo.

Se os usuários estiverem carregando arquivos, a postagem HTTP conterá o tipo MIME do arquivo juntamente com os dados. Por exemplo, o Django disponibiliza esses dados como um atributo do objeto UploadedFile .

Dave Webb
fonte
12
Se os arquivos estiverem armazenados em BLOBs, conforme especificado na pergunta, talvez você não conheça a extensão do arquivo.
Caracol mecânico
55
As extensões de arquivo não são uma maneira confiável de determinar o tipo de mímica.
Cerin
12
import mimetypes mimetypes.MimeTypes().guess_type(filename)[0]
Jonathan
4
no python 3.6, isso funciona:mimetypes.guess_type(path_file_to_upload)[1]
JinSnow 16/03
3
Embora o @cerin esteja certo de que as extensões de arquivo não são confiáveis, eu acabei de descobrir que a precisão de python-magic(como sugerido na resposta superior) é ainda menor, conforme confirmado em github.com/s3tools/s3cmd/issues/198 . Então, mimetypesparece um candidato melhor para mim.
Danqing 07/08/19
46

Uma maneira mais confiável do que usar a biblioteca mimetypes seria usar o pacote python-magic.

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

Isso seria equivalente ao uso do arquivo (1).

No Django, também é possível garantir que o tipo MIME corresponda ao do UploadedFile.content_type.

toivotuo
fonte
2
Veja o post de Simon Zimmermann para um uso atualizado da python-magic
Daren Thomas
@ DarenThomas: Como mencionado na resposta de mammadori, essa resposta não está desatualizada e distinta da solução de Simon Zimmermann. Se você tiver o utilitário de arquivos instalado, provavelmente poderá usar esta solução. Funciona para mim com o arquivo 5.32. No gentoo, você também deve ter o python USE-flag habilitado para o pacote de arquivos.
bodo
35

Isso parece ser muito 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)

Consulte o Post Antigo

Atualização - Conforme comentário do @Garrets, no python 3 é mais simples:

import mimetypes
print(mimetypes.guess_type("sample.html"))
Laxmikant Ratnaparkhi
fonte
4
Eu não acho que o urllib seja necessário no seu exemplo.
BrotherJack
5
para Python 3.X, substitua import urllib pela solicitação de importação urllib. E, em seguida, usar o "pedido" em vez de urllib
Arjun Thakur
1
Funciona para o python 2.7 também
Jay Modi
A solução do @ oetzi usa esse módulo, mas é mais simples.
Garrett
11

Existem 3 bibliotecas diferentes que agrupam a libmagic.

2 deles estão disponíveis no pypi (para que a instalação do pip funcione):

  • filemagic
  • python-magic

E outro, semelhante ao python-magic, está disponível diretamente nas fontes libmagic mais recentes, e é o que você provavelmente possui em sua distribuição linux.

No Debian, o pacote python-magic é sobre esse e é usado como o toivotuo disse e não é obsoleto como Simon Zimmermann disse (IMHO).

Parece-me outra visão (do autor original da libmagic).

Pena que não está disponível diretamente no pypi.

mammadori
fonte
Eu adicionei um repo por conveniência: github.com/mammadori/magic-python de que maneira você pode: pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
mammadori
10

no python 2.6:

mime = subprocess.Popen("/usr/bin/file --mime PATH", shell=True, \
    stdout=subprocess.PIPE).communicate()[0]
apito
fonte
6
Isso é desnecessário, pois o filecomando é basicamente apenas um invólucro da libmagic. Você também pode usar a ligação python (python-magic), como na resposta de Simon.
Caracol mecânico
6
Isso depende do sistema operacional. No Mac OS X, por exemplo, você tem "arquivo", mas não libmagic no ambiente normal.
Rptb1
9

Atualização de 2017

Não é necessário acessar o github, ele está no PyPi com um nome diferente:

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

O código também pode ser simplificado:

>>> import magic

>>> magic.from_file('/tmp/img_3304.jpg', mime=True)
'image/jpeg'
Gringo Suave
fonte
você pode fazer o mesmo para o arquivo js ou css?
kumbhanibhavesh
Claro, por que não??
Gringo Suave
9

Ligações Python ao libmagic

Todas as respostas diferentes sobre este tópico são muito confusas, então espero dar um pouco mais de clareza com esta visão geral das diferentes ligações da libmagic. Anteriormente, mammadori deu uma resposta curta listando a opção disponível.

libmagic

Ao determinar um tipo MIME de arquivos, a ferramenta de escolha é simplesmente chamada filee seu back-end é chamado libmagic. (Veja a página inicial do projeto .) O projeto é desenvolvido em um repositório cvs privado, mas há um espelho git somente leitura no github .

Agora, esta ferramenta, que você precisará se desejar usar qualquer uma das ligações libmagic com python, já vem com suas próprias ligações python chamadas file-magic. Não há muita documentação dedicado para eles, mas você pode sempre ter um olhar para a página do manual do c-biblioteca: man libmagic. O uso básico é descrito no arquivo leia - me :

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)

Além disso, você também pode usar a biblioteca criando um Magicobjeto usando magic.open(flags)como mostrado no arquivo de exemplo .

O toivotuo e o ewr2san usam essas file-magicligações incluídas na fileferramenta. Eles assumem erroneamente que estão usando o python-magicpacote. Isso parece indicar que, se ambos filee python-magicestiverem instalados, o módulo python magicse refere ao anterior.

python-magic

Esta é a biblioteca que Simon Zimmermann fala em sua resposta e que também é empregada por Claude COULOMBE e Gringo Suave .

filemagic

Nota : Este projeto foi atualizado pela última vez em 2013!

Por se basear no mesmo c-api, esta biblioteca tem alguma semelhança com o file-magicincluído no libmagic. Só é mencionado por mammadori e nenhuma outra resposta o emprega.

bodo
fonte
7

O método do @toivotuo funcionou melhor e mais confiável para mim no python3. Meu objetivo era identificar arquivos compactados com gzip que não possuem uma extensão .gz confiável. Eu instalei o 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 um arquivo compactado com gzip, ele retorna: application / gzip; charset = binário

para um arquivo txt descompactado (dados do iostat): texto / sem formatação; charset = us-ascii

para um arquivo tar: application / x-tar; charset = binário

para um arquivo bz2: application / x-bzip2; charset = binário

e por último mas não menos importante, um arquivo .zip: application / zip; charset = binário

ewr2san
fonte
7

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

mimetypes.guess_type (url, strict = True) Adivinha o tipo de arquivo com base em seu nome de arquivo ou URL, fornecido por url. O valor de retorno é uma tupla (tipo, codificação) em que tipo é Nenhum se o tipo não puder ser adivinhado (sufixo ausente ou desconhecido) ou uma sequência do formato 'tipo / subtipo', utilizável para um cabeçalho do tipo de conteúdo MIME.

codificação é Nenhum para nenhuma codificação ou o nome do programa usado para codificar (por exemplo, compactar ou gzip). A codificação é adequada para uso como um cabeçalho de codificação de conteúdo, não como um cabeçalho de codificação de transferência de conteúdo. Os mapeamentos são orientados por tabela. Os sufixos de codificação diferenciam maiúsculas de minúsculas; os sufixos de tipo são testados primeiro com distinção entre maiúsculas e minúsculas e depois sem maiúsculas e minúsculas.

O argumento estrito opcional é um sinalizador que especifica se a lista de tipos MIME conhecidos é limitada apenas aos tipos oficiais registrados na IANA. Quando strict é True (o padrão), apenas os tipos de IANA são suportados; Quando strict é False, alguns tipos MIME não padronizados, mas geralmente usados, também são reconhecidos.

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

Você não indicou qual servidor da Web estava usando, mas o Apache possui um pequeno módulo chamado Mime Magic, que é usado para determinar o tipo de arquivo quando solicitado. Ele lê parte do conteúdo do arquivo e tenta descobrir que tipo ele é baseado nos caracteres encontrados. E como Dave Webb mencionou, o MimeTypes Module em python funcionará, desde que uma extensão seja útil.

Como alternativa, se você estiver sentado em uma caixa UNIX, poderá usar sys.popen('file -i ' + fileName, mode='r')para pegar o tipo MIME. O Windows deve ter um comando equivalente, mas não tenho certeza sobre o que é.

Akdom
fonte
7
Hoje em dia você pode simplesmente executar subprocess.check_output (['file', '-b', '--mime', filename]) '
Nathan Villaescusa
Não há realmente nenhuma razão para recorrer ao uso de uma ferramenta externa quando o python-magic faz a coisa equivalente, tudo embrulhado e aconchegante.
039:
4

No Python 3.xe webapp com URL para o arquivo que não poderia ter uma extensão ou uma extensão falsa. Você deve instalar o python-magic, usando

pip3 install python-magic

No Mac OS X, você também deve instalar a 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)

Como alternativa, você pode colocar um tamanho na leitura

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
fonte
Será que vai carregar o arquivo inteiro?
吴毅凡
Não, é um fluxo, normalmente apenas alguns bytes.
Claude COULOMBE
Editei por response.readline () ou response.read (128) Obrigado!
Claude COULOMBE 25/03
3

Eu tento a biblioteca de tipos MIME primeiro. Se não estiver funcionando, eu uso a biblioteca 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
Jak Liao
fonte
1

O módulo mimetypes apenas reconhece um tipo de arquivo com base na extensão do arquivo. Se você tentar recuperar um tipo de arquivo sem extensão, os tipos MIME não funcionarão.

Helder
fonte
3
Eu não acho que isso seja verdade. O tipo MIME é sobre como informar os outros sobre um formato de dados, não sobre como descobrir você mesmo. Se você usar uma ferramenta que adivinha o formato apenas com base na extensão e imprimir tipos MIME, não poderá usá-la se não houver extensões de arquivo. Mas outras formas de adivinhar o formato também são possíveis, por exemplo, verificando com um analisador.
precisa
1

Estou surpreso que ninguém tenha mencionado isso, mas a Pygments é capaz de adivinhar o tipo mímico de, particularmente, documentos de texto.

Pygments é na verdade uma biblioteca de realce de sintaxe Python, mas possui um método que dará um palpite sobre qual dos 500 tipos de documentos suportados é o seu documento. ou seja, 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)

Resultado:

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

Agora, não é perfeito, mas se você precisar saber qual dos 500 formatos de documento está sendo usado, isso é bastante útil.

Eric McLachlan
fonte
0

Eu tentei muitos exemplos, mas com o Django o mutagen toca bem.

Exemplo verificando se os arquivos estão mp3

from mutagen.mp3 import MP3, HeaderNotFoundError  

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

A desvantagem é que sua capacidade de verificar os tipos de arquivo é limitada, mas é uma ótima maneira, se você deseja não apenas verificar o tipo de arquivo, mas também acessar informações adicionais.

Artem Bernatskyi
fonte
eu preciso verificar segurança também
Artem Bernatskyi
0

Para dados do tipo Matriz de bytes, você pode usar magic.from_buffer (_byte_array, mime = True)

Superusuário
fonte
-1

você pode usar o módulo imghdr Python.

jianpx
fonte
1
Este não é um comentário útil, porque não fornece exemplos nem diz realmente como ou por que o imghdr ajudaria aqui.
Erikbwork
2
Sim eu entendo isso. Já faz mais de um ano, mas talvez você ainda possa atualizá-lo, porque ainda há pessoas procurando por essa pergunta, como eu. Se você precisar de ajuda, pode me dizer.
Erikbwork
1
Funciona apenas para uma lista muito limitada de tipos de imagem. Não tem idéia sobre arquivos de texto, arquivos compactados, formatos de documento etc.
tripleee