Read this blog post in English.
O conteúdo desse artigo está disponível também em vídeo:
Alguns dos usuários da minha biblioteca rows me pediram funcionalidades de detecção de encoding e tipo de arquivo, então comecei a procurar alguma biblioteca Python simples e rápida que desse conta dessa tarefa. O problema: encontrei muitas bibliotecas e nenhuma delas me atraiu por alguns dos seguintes motivos:
- Não tinha uma implementação pythônica;
- Não estava disponível no Debian (se eu usasse o pacote rows no Debian iria quebrar);
- Não estava sendo mantida atualmente;
- Não funcionava corretamente.
Então percebi que não existe uma "solução de ouro" para esse problema em Python. Muitos pythonistas usam a biblioteca chardet, mas ela detecta muitas vezes com erros e é razoavelmente lenta (principalmente se você precisar fazer a detecção enquanto um usuário aguarda a resposta através de uma chamada de API via HTTP) -- veja mais detalhes sobre isso no vídeo.
But there should be one -- and preferably only one -- obvious way to do it.
Então, eu pensei: por que não usar o programa file
, que já
é bastante conhecido por hackers do mundo UNIX, é rápido e muito mais assertivo
que todas as outras opções? Para minha surpresa não existia um bom binding de
Python para a libmagic
(algumas bibliotecas rodavam o comando file
mas
isso não era uma opção para mim pois dependia de mais um pacote do sistema e
não era uma solução muito portável).
Depois de vasculhar o repositório de código do file
eu encontrei
um binding simples para Python, que na época não
estava disponível no PyPI e não era tão pythônica como eu
esperava.
A Solução
Como o código é software livre, eu criei uma issue no
sistema de bugs do file
para resolver o problema e o
Christos Zoulas (atual mantenedor) me pediu um patch, que
eu implementei, enviei e foi aceito. :-)
Fiquei muito feliz de poder colaborar com um software importante e que eu uso
desde de meus primeiros passos no mundo GNU/Linux (2003? 2004?)! Durante minha
busca eu descobri que o primeiro commit da versão livre do file
é de 1987
(eu tinha menos de 4 meses de idade!) -- e o software ainda é mantido hoje.
Agora todos podemos usar binding oficial do file
para
Python: a nova biblioteca é chamada file-magic
e pode ser
instalada executando:
pip install file-magic
Ela disponibiliza várias funções e atributos, mas as mais importantes são bem
simples e intuitivas: elas retornam uma namedtuple
com os
resultados da detecção. Vamos ao código!
>>> import magic
>>> # Você pode especificar diretamente um nome de arquivo
>>> filename_detected = magic.detect_from_filename('turicas.jpg')
>>> print(filename_detected)
FileMagic(mime_type='image/jpeg', encoding='binary',
name='JPEG image data, JFIF standard 1.02, aspect ratio, density 1x1, segment length 16, progressive, precision 8, 842x842, frames 3')
>>> # E você pode acessar os atributos da `namedtuple`:
>>> print(filename_detected.mime_type)
image/jpeg
# E se você já tem o conteúdo do arquivo em memória:
>>> with open('data.html') as fobj:
... data = fobj.read()
>>> content_detected = magic.detect_from_content(data)
>>> print(content_detected)
FileMagic(mime_type='text/html', encoding='utf-8',
name='HTML document, UTF-8 Unicode text')
>>> print(content_detected.encoding)
utf-8
Algumas coisas ainda precisam ser melhoradas (como a documentação, rodar os
testes em outras plataformas etc.), porém a biblioteca já pode ser instalada
através do pip
, é rápida e precisa. :-)
Espero que vocês tenham gostado! ;-)