Jak znaleźć typ MIME pliku w Pythonie?


194

Powiedzmy, że chcesz gdzieś zapisać kilka plików, na przykład w BLOBach. Powiedzmy, że chcesz udostępnić te pliki za pośrednictwem strony internetowej i pozwolić klientowi automatycznie otworzyć poprawną aplikację / przeglądarkę.

Założenie: przeglądarka ustala, która aplikacja / przeglądarka ma użyć nagłówka mime-type (content-type?) W odpowiedzi HTTP.

Opierając się na tym założeniu, oprócz bajtów pliku, chcesz również zapisać typ MIME.

Jak znajdziesz typ pliku MIME? Jestem obecnie na komputerze Mac, ale powinno to również działać w systemie Windows.

Czy przeglądarka dodaje tę informację podczas publikowania pliku na stronie internetowej?

Czy jest fajna biblioteka Pythona do wyszukiwania tych informacji? WebService lub (jeszcze lepiej) baza danych do pobrania?

Odpowiedzi:


218

Metoda magii python sugerowana przez toivotuo jest nieaktualna. Obecny pień Pythona-magii znajduje się w Github i na podstawie readme, znajdowanie typu MIME, odbywa się w ten sposób.

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

17
Dziękuję za komentarz! należy pamiętać, że „powyżej” jest trudnym pojęciem w przepełnieniu stosu, ponieważ porządkowanie jest grupowane według głosów i losowo rozmieszczane w grupach. Zgaduję, że odwołujesz się do odpowiedzi @ toivotuo.
Daren Thomas

1
Tak, nie miałem wystarczającej liczby „punktów”, aby móc pisać komentarze w momencie pisania tej odpowiedzi. Ale prawdopodobnie powinienem napisać to jako komentarz, aby @toivotuo mógł edytować jego pytanie.
Simon Zimmermann

1
rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL: darwinsys.com/file Podsumowanie: Powiązania Python dla libmagic API rpm -qf / usr / bin / file -i Nazwa: plik URL: darwinsys.com/file python-magic z darwinsys.com/file, który jest dostarczany z Linuksem Fedora działa podobnie jak @ toivotuo. I wydaje się bardziej głównym strumieniem.
Sérgio

7
Uważaj, że pakiet debian / ubuntu o nazwie python-magic różni się od pakietu pip o tej samej nazwie. Oba są, import magicale mają niezgodne treści. Aby uzyskać więcej informacji, zobacz stackoverflow.com/a/16203777/3189 .
Hamish Downer

1
Jak skomentowałem odpowiedź toivotuo, nie jest ona nieaktualna! Mówisz o innej bibliotece. Czy możesz usunąć lub zastąpić to oświadczenie w swojej odpowiedzi? W tej chwili znalezienie najlepszego rozwiązania jest naprawdę trudne.
Bodo

87

W MIMETYPES moduł w bibliotece standardowej zadecyduje / odgadnąć typ MIME z rozszerzeniem pliku.

Jeśli użytkownicy przesyłają pliki, post HTTP będzie zawierał typ MIME pliku obok danych. Na przykład Django udostępnia te dane jako atrybut obiektu UploadedFile .


12
Jeśli pliki są przechowywane w obiektach BLOB, jak określono w pytaniu, rozszerzenie pliku może nie być znane.
Ślimak mechaniczny

55
Rozszerzenia plików nie są niezawodnym sposobem na określenie typu MIME.
Cerin,

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

4
w Pythonie 3.6 działa to:mimetypes.guess_type(path_file_to_upload)[1]
JinSnow,

3
Podczas gdy @cerin ma rację, że rozszerzenia plików nie są niezawodne, właśnie odkryłem, że dokładność python-magic(jak sugerowano w górnej odpowiedzi) jest jeszcze niższa, co potwierdza github.com/s3tools/s3cmd/issues/198 . Tak więc, mimetypeswydaje się lepszym kandydatem do mnie.
Danqing,

46

Bardziej niezawodnym sposobem niż użycie biblioteki mimetypes byłoby użycie pakietu python-magic.

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

Byłoby to równoważne z użyciem file (1).

W Django można również upewnić się, że typ MIME jest zgodny z typem UploadedFile.content_type.


2
Zobacz post Simona Zimmermanna o zaktualizowanym zastosowaniu magii python
Daren Thomas

@DarenThomas: Jak wspomniano w odpowiedzi mammadori, ta odpowiedź nie jest przestarzała i nie różni się od rozwiązania Simona Zimmermanna. Jeśli masz zainstalowane narzędzie do plików, prawdopodobnie możesz skorzystać z tego rozwiązania. Działa dla mnie z plikiem 5.32. W Gentoo musisz mieć włączoną flagę python USE dla pakietu plików.
Bodo

36

To wydaje się bardzo łatwe

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

Proszę odnieś się Old Post

Aktualizacja - zgodnie z komentarzem @Garrets w Pythonie 3 jest to prostsze:

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

4
Nie sądzę, aby adres URL był wymagany w twoim przykładzie.
BrotherJack,

5
dla Python 3.X zamień import urllib na z żądania importu urllib. A następnie użyj „request” zamiast urllib
Arjun Thakur

1
Działa również dla Pythona 2.7
Jay Modi

@ oetzi męska rozwiązanie wykorzystuje ten moduł, ale jest bardziej proste.
Garrett,

11

Istnieją 3 różne biblioteki, które zawierają libmagic.

2 z nich są dostępne na pypi (więc instalacja pip będzie działać):

  • filemagiczny
  • python-magic

Kolejny, podobny do python-magic, jest dostępny bezpośrednio w najnowszych źródłach libmagic i jest to ten, który prawdopodobnie masz w swojej dystrybucji linux.

W Debianie pakiet o python-magic dotyczy właśnie tego i jest używany jako toivotuo powiedział i nie jest przestarzały, jak powiedział Simon Zimmermann (IMHO).

Wydaje mi się, że to kolejne ujęcie (autorstwa oryginalnego autora libmagic).

Szkoda, że ​​nie jest dostępny bezpośrednio na pypi.


Dodałem repozytorium dla wygody: github.com/mammadori/magic-python w ten sposób możesz: pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
mammadori

10

w Pythonie 2.6:

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

6
Jest to niepotrzebne, ponieważ filepolecenie to po prostu opakowanie na libmagic. Równie dobrze możesz użyć wiązania python (python-magic), jak w odpowiedzi Simona.
Ślimak mechaniczny

6
To zależy od systemu operacyjnego. Na przykład w Mac OS X masz „plik”, ale nie ma libmagic w normalnym środowisku.
rptb1

9

Aktualizacja 2017

Nie musisz iść do github, jest na PyPi pod inną nazwą:

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

Kod można również uprościć:

>>> import magic

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

czy możesz zrobić to samo dla pliku js lub css?
kumbhanibhavesh

Jasne, czemu nie??
Gringo Suave,

9

Powiązania Pythona z libmagic

Wszystkie różne odpowiedzi na ten temat są bardzo mylące, więc mam nadzieję, że dam nieco więcej jasności dzięki przeglądowi różnych powiązań libmagic. Wcześniej mammadori udzielił krótkiej odpowiedzi listą dostępnej opcji.

libmagic

Podczas określania typu pliku MIME wybrane narzędzie jest po prostu wywoływane filei wywoływane jest jego zaplecze libmagic. (Zobacz stronę główną projektu .) Projekt jest rozwijany w prywatnym repozytorium cvs, ale na github znajduje się tylko do odczytu mirror git .

Teraz to narzędzie, które będzie potrzebne, jeśli chcesz używać dowolnego z powiązań libmagic z pythonem, ma już swoje własne, zwane powiązania z pythonem file-magic. Nie ma zbyt wiele dedykowana dokumentacja dla nich, ale zawsze można rzucić okiem na stronę man c-biblioteki: man libmagic. Podstawowe użycie opisano w pliku 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)

Oprócz tego możesz również korzystać z biblioteki, tworząc Magicobiekt za pomocą, magic.open(flags)jak pokazano w przykładowym pliku .

Zarówno toivotuo, jak i ewr2san używają tych file-magicwiązań zawartych w filenarzędziu. Błędnie zakładają, że używają python-magicpakietu. Wydaje się to wskazywać, że jeśli oba filei python-magicsą instalowane, moduł python magicodnosi się do tej pierwszej.

python-magic

Jest to biblioteka, o której mówi Simon Zimmermann w swojej odpowiedzi i która jest również wykorzystywana przez Claude'a COULOMBE, a także Gringo Suave .

filemagiczny

Uwaga : ten projekt został ostatnio zaktualizowany w 2013 roku!

Ponieważ ta biblioteka oparta jest na tym samym c-api, ma pewne podobieństwo z file-magiczawartą w libmagic. Wspomina o tym tylko mammadori i żadna inna odpowiedź go nie stosuje.


7

Metoda @toivotuo działała najlepiej i najbardziej niezawodnie dla mnie w Python3. Moim celem było zidentyfikowanie plików spakowanych gzip, które nie mają niezawodnego rozszerzenia .gz. Zainstalowałem 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))

dla pliku spakowanego gzipem zwraca: application / gzip; charset = binarny

dla rozpakowanego pliku txt (dane iostat): text / plain; charset = us-ascii

dla pliku tar: application / x-tar; charset = binarny

dla pliku bz2: application / x-bzip2; charset = binarny

i dla mnie wreszcie plik .zip: application / zip; charset = binarny


7

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

mimetypes.guess_type (url, strict = True) Odgadnij typ pliku na podstawie jego nazwy pliku lub adresu URL podanego przez adres url. Zwracana wartość to krotka (typ, kodowanie), gdzie typ to Brak, jeśli nie można zgadnąć typu (brakujący lub nieznany sufiks) lub ciąg znaków „typ / podtyp”, nadający się do nagłówka typu treści MIME.

kodowanie to Brak, brak kodowania lub nazwa programu użytego do kodowania (np. kompresja lub gzip). Kodowanie nadaje się do użycia jako nagłówek kodowania treści, a nie jako nagłówek kodowania treści. Odwzorowania są oparte na tabeli. W przyrostkach kodowania rozróżniana jest wielkość liter; sufiksy typów są najpierw sprawdzane z rozróżnianiem wielkości liter, a następnie bez rozróżniania wielkości liter.

Opcjonalny ścisły argument jest flagą określającą, czy lista znanych typów MIME jest ograniczona tylko do oficjalnych typów zarejestrowanych w IANA. Gdy strict ma wartość True (domyślnie), obsługiwane są tylko typy IANA; gdy strict jest False, rozpoznawane są również dodatkowe niestandardowe, ale często używane typy MIME.

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

6

Nie określiłeś, jakiego serwera używasz, ale Apache ma ładny mały moduł o nazwie Mime Magic, którego używa do określania typu pliku, gdy zostanie o to poproszony. Odczytuje część zawartości pliku i próbuje dowiedzieć się, jakiego typu jest on na podstawie znalezionych znaków. I jak Dave Webb Wspomniany przez MIMETYPES modułu pod pytona będzie działać pod warunkiem, rozszerzenie jest poręczny.

Alternatywnie, jeśli siedzisz na pudełku UNIX, możesz użyć sys.popen('file -i ' + fileName, mode='r')do przechwycenia typu MIME. Windows powinien mieć równoważne polecenie, ale nie jestem pewien, co to jest.


7
W dzisiejszych czasach możesz po prostu zrobić subprocess.check_output ([„plik”, „-b”, „--mime”, nazwa pliku])
Nathan Villaescusa

Naprawdę nie ma powodu, aby używać zewnętrznego narzędzia, gdy magia python robi to samo, wszystko jest przytulne i przytulne.
cholera

4

W Pythonie 3.x i aplikacji internetowej z adresem URL do pliku, który nie może mieć rozszerzenia ani fałszywego rozszerzenia. Powinieneś zainstalować Python-Magic, używając

pip3 install python-magic

W systemie Mac OS X należy również zainstalować libmagic przy użyciu

brew install libmagic

Fragment kodu

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)

alternatywnie możesz wstawić rozmiar do odczytu

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)

Czy zostanie załadowany cały plik?
吴毅 凡

Nie, to strumień, więc zwykle tylko kilka bajtów.
Claude COULOMBE,

Edytowałem przez response.readline () lub response.read (128) Dziękujemy!
Claude COULOMBE,

3

Najpierw próbuję biblioteki mimetypes. Jeśli to nie działa, używam zamiast tego biblioteki 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

Moduł mimetypes po prostu rozpoznaje typ pliku na podstawie rozszerzenia pliku. Jeśli spróbujesz odzyskać typ pliku bez rozszerzenia, typy MIME nie będą działać.


3
Nie sądzę, że to prawda. Typ MIME polega na tym, jak powiedzieć innym o formacie danych, a nie na tym, jak samemu znaleźć format danych. Jeśli używasz narzędzia, które zgaduje format tylko na podstawie rozszerzenia i drukuje typy MIME, nie możesz użyć tego narzędzia, jeśli nie ma rozszerzeń plików. Możliwe są jednak również inne sposoby odgadnięcia formatu, np. Sprawdzenie za pomocą analizatora składni.
erikbwork

1

Dziwię się, że nikt o tym nie wspominał, ale Pygments potrafi zgadywać na temat typu mimów, szczególnie dokumentów tekstowych.

Pygments to tak naprawdę biblioteka do podświetlania składni Pythona, ale ma metodę, która pozwoli odgadnąć, który z 500 obsługiwanych typów dokumentów jest twoim dokumentem. tj. c ++ vs C # vs Python vs itp

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)

Wynik:

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

Teraz nie jest idealny, ale jeśli chcesz wiedzieć, który z 500 formatów dokumentów jest używany, jest to bardzo przydatne.


0

Próbowałem wielu przykładów, ale z mutagenem Django gra się ładnie.

Przykład sprawdzania, czy pliki są mp3

from mutagen.mp3 import MP3, HeaderNotFoundError  

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

Minusem jest to, że możliwość sprawdzania typów plików jest ograniczona, ale jest to świetny sposób, jeśli chcesz nie tylko sprawdzić typ pliku, ale także uzyskać dostęp do dodatkowych informacji.


Muszę również sprawdzić bezpieczeństwo
Artem Bernatskyi


0

W przypadku danych typu Array bajtów można użyć magic.from_buffer (_byte_array, mime = True)


-1

możesz użyć modułu imghdr Python.


1
To nie jest pomocny komentarz, ponieważ nie podaje przykładów ani nie mówi, jak i dlaczego imghdr miałby tutaj pomóc.
erikbwork

2
Tak rozumiem to. To już ponad rok temu, ale może nadal możesz je zaktualizować, ponieważ wciąż są ludzie szukający tego pytania, jak ja. Jeśli potrzebujesz pomocy, możesz mi powiedzieć.
erikbwork,

1
Działa tylko w przypadku bardzo ograniczonej listy typów obrazów. Nie ma pojęcia o plikach tekstowych, skompresowanych archiwach, formatach dokumentów itp.
tripleee
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.