Bagaimana cara menemukan tipe mime file dalam python?

194

Katakanlah Anda ingin menyimpan banyak file di suatu tempat, misalnya di BLOB. Katakanlah Anda ingin mengeluarkan file-file ini melalui halaman web dan klien secara otomatis membuka aplikasi / penampil yang benar.

Asumsi: Peramban mengetahui aplikasi / penampil mana yang akan digunakan oleh header tipe-mime (tipe-konten?) Dalam respons HTTP.

Berdasarkan asumsi itu, selain byte file, Anda juga ingin menyimpan tipe MIME.

Bagaimana Anda menemukan jenis file MIME? Saya saat ini menggunakan Mac, tetapi ini juga harus bekerja pada Windows.

Apakah browser menambahkan informasi ini ketika memposting file ke halaman web?

Apakah ada perpustakaan python yang rapi untuk menemukan informasi ini? Layanan Web atau (bahkan lebih baik) database yang dapat diunduh?

Daren Thomas
sumber

Jawaban:

218

Metode python-magic yang disarankan oleh toivotuo sudah usang. Trunk Python-magic saat ini ada di Github dan berdasarkan readme di sana, menemukan tipe MIME, dilakukan seperti ini.

# For MIME types
import magic
mime = magic.Magic(mime=True)
mime.from_file("testdata/test.pdf") # 'application/pdf'
Simon Zimmermann
sumber
17
terima kasih atas komentarnya! harap dicatat, bahwa "di atas" adalah konsep yang sulit dalam stackoverflow, karena pemesanan dikelompokkan berdasarkan suara dan dipesan secara acak di dalam grup. Saya kira Anda merujuk ke jawaban @ toivotuo.
Daren Thomas
1
Yeh, saya tidak punya cukup "poin" untuk membuat komentar pada saat menulis balasan ini. Tapi saya mungkin harus menulisnya sebagai komentar, sehingga @toivotuo bisa mengedit pertanyaannya.
Simon Zimmermann
1
rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL: darwinsys.com/file Ringkasan: binding Python untuk API libmagic rpm rpm -qf / usr / bin / file -i Nama: file URL: darwinsys.com/file python-magic dari darwinsys.com/file dan yang datang dengan Linux Fedora bekerja seperti kata @ toivotuo. Dan sepertinya aliran lebih utama.
Sérgio
7
Waspadalah bahwa paket debian / ubuntu yang disebut python-magic berbeda dengan paket pip dengan nama yang sama. Keduanya import magictetapi memiliki konten yang tidak kompatibel. Lihat stackoverflow.com/a/16203777/3189 untuk lebih lanjut.
Hamish Downer
1
Saat saya mengomentari jawaban toivotuo, itu tidak ketinggalan zaman! Anda berbicara tentang perpustakaan yang berbeda. Bisakah Anda menghapus atau mengganti pernyataan itu dalam jawaban Anda? Saat ini membuat mencari solusi terbaik sangat sulit.
Bodo
86

The Mimetypes modul di perpustakaan standar akan menentukan / menebak tipe MIME dari ekstensi file.

Jika pengguna mengunggah file, posting HTTP akan berisi tipe MIME dari file di samping data. Misalnya, Django membuat data ini tersedia sebagai atribut dari objek UploadedFile .

Dave Webb
sumber
12
Jika file disimpan dalam BLOB, seperti yang ditentukan dalam pertanyaan, Anda mungkin tidak tahu ekstensi file.
Siput mekanik
55
Ekstensi file bukan cara yang andal untuk menentukan tipe mime.
Cerin
12
import mimetypes mimetypes.MimeTypes().guess_type(filename)[0]
Jonathan
4
dalam python 3.6 ini bekerja:mimetypes.guess_type(path_file_to_upload)[1]
JinSnow
3
Meskipun @cerin benar bahwa ekstensi file tidak dapat diandalkan, saya baru saja menemukan bahwa keakuratan python-magic(seperti yang disarankan dalam jawaban atas) menjadi lebih rendah, seperti yang dikonfirmasi oleh github.com/s3tools/s3cmd/issues/198 . Jadi, mimetypessepertinya kandidat yang lebih baik untuk saya.
danqing
46

Cara yang lebih andal daripada menggunakan mimetypes library adalah dengan menggunakan paket python-magic.

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

Ini akan setara dengan menggunakan file (1).

Pada Django kita juga bisa memastikan bahwa tipe MIME cocok dengan yang diunggah dari UploadedFile.content_type.

toivotuo
sumber
2
Lihat posting Simon Zimmermann untuk penggunaan python-magic yang diperbarui
Daren Thomas
@DarenThomas: Sebagaimana disebutkan dalam jawaban mammadori, jawaban ini tidak ketinggalan zaman dan berbeda dari solusi Simon Zimmermann. Jika Anda telah menginstal utilitas file, Anda mungkin dapat menggunakan solusi ini. Ini berfungsi untuk saya dengan file-5.32. Pada gentoo, Anda juga harus mengaktifkan flag USE python untuk paket file.
Bodo
35

Ini tampaknya sangat mudah

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

Silakan merujuk Old Post

Perbarui - Sesuai komentar @Garrets, Dalam python 3 lebih mudah:

import mimetypes
print(mimetypes.guess_type("sample.html"))
Laxmikant Ratnaparkhi
sumber
4
Saya tidak berpikir urllib diperlukan dalam contoh Anda.
BrotherJack
5
untuk Python 3.X ganti impor urllib dengan dari permintaan impor urllib. Dan kemudian gunakan "permintaan" alih-alih urllib
Arjun Thakur
1
Bekerja untuk python 2.7 juga
Jay Modi
@ Oetzi ini solusi menggunakan modul ini, tetapi lebih sederhana.
Garrett
11

Ada 3 perpustakaan berbeda yang membungkus libmagic.

2 di antaranya tersedia di pypi (jadi instalasi pip akan berfungsi):

  • filemagis
  • python-magic

Dan yang lain, mirip dengan python-magic tersedia langsung di sumber libmagic terbaru, dan itu adalah yang mungkin Anda miliki dalam distribusi linux Anda.

Dalam Debian paket python-magic adalah tentang yang satu ini dan digunakan seperti kata toivotuo dan tidak usang seperti kata Simon Zimmermann (IMHO).

Sepertinya saya ambil lagi (oleh penulis asli libmagic).

Sayang sekali tidak tersedia langsung di pypi.

mammadori
sumber
Saya menambahkan repo untuk kenyamanan: github.com/mammadori/magic-python dengan cara itu Anda dapat: pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
mammadori
10

dalam python 2.6:

mime = subprocess.Popen("/usr/bin/file --mime PATH", shell=True, \
    stdout=subprocess.PIPE).communicate()[0]
apito
sumber
6
Ini tidak perlu, karena fileperintah pada dasarnya hanyalah pembungkus libmagic. Anda mungkin juga hanya menggunakan penjilidan python (python-magic), seperti dalam jawaban Simon.
Siput mekanik
6
Itu tergantung pada sistem operasi. Pada Mac OS X, misalnya, Anda memiliki "file" tetapi tidak libmagic di lingkungan normal.
rptb1
9

Pembaruan 2017

Tidak perlu pergi ke github, itu di PyPi dengan nama yang berbeda:

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

Kode dapat disederhanakan juga:

>>> import magic

>>> magic.from_file('/tmp/img_3304.jpg', mime=True)
'image/jpeg'
Gringo Suave
sumber
dapatkah Anda melakukan hal yang sama untuk file js atau css?
kumbhanibhavesh
Tentu saja mengapa tidak??
Gringo Suave
9

Binding Python untuk libmagic

Semua jawaban yang berbeda pada topik ini sangat membingungkan, jadi saya berharap untuk memberikan sedikit lebih banyak kejelasan dengan ikhtisar ini tentang berbagai ikatan libmagic. Sebelumnya mammadori memberi jawaban singkat mencantumkan opsi yang tersedia.

libmagic

Saat menentukan jenis file mime, alat pilihan dipanggil filedan back-endnya disebut libmagic. (Lihat halaman depan Proyek .) Proyek ini dikembangkan di repositori cvs pribadi, tetapi ada mirror git read-only di github .

Sekarang alat ini, yang akan Anda perlukan jika Anda ingin menggunakan binding libmagic dengan python, sudah dilengkapi dengan binding python sendiri yang disebut file-magic. Tidak ada banyak dokumentasi yang didedikasikan untuk mereka, tetapi Anda selalu dapat kita lihat pada halaman manual dari c-library: man libmagic. Penggunaan dasar dijelaskan dalam file 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)

Selain itu, Anda juga dapat menggunakan perpustakaan dengan membuat Magicobjek menggunakan magic.open(flags)seperti yang ditunjukkan pada file contoh .

Baik toivotuo dan ewr2san menggunakan file-magicbinding ini termasuk dalam filealat. Mereka keliru menganggap, mereka menggunakan python-magicpaket itu. Ini tampaknya menunjukkan, bahwa jika keduanya filedan python-magicdiinstal, modul python magicmerujuk ke yang sebelumnya.

python-magic

Ini adalah perpustakaan yang dibicarakan Simon Zimmermann dalam jawabannya dan yang juga digunakan oleh Claude COULOMBE serta Gringo Suave .

filemagis

Catatan : Proyek ini terakhir diperbarui pada 2013!

Karena didasarkan pada c-api yang sama, perpustakaan ini memiliki beberapa kesamaan dengan yang file-magictermasuk dalam libmagic. Itu hanya disebutkan oleh mammadori dan tidak ada jawaban lain yang mempekerjakannya.

bodo
sumber
7

Metode @toivotuo bekerja paling baik dan paling andal bagi saya di bawah python3. Tujuan saya adalah mengidentifikasi file gzip yang tidak memiliki ekstensi .gz yang andal. Saya menginstal 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))

untuk file yang gzip dikembalikan: application / gzip; charset = biner

untuk file txt yang tidak di-zip (data iostat): text / plain; charset = us-ascii

untuk file tar: application / x-tar; charset = biner

untuk file bz2: application / x-bzip2; charset = biner

dan yang tak kalah pentingnya bagi saya file .zip: application / zip; charset = biner

ewr2san
sumber
7

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

mimetypes.guess_type (url, strict = True) Tebak jenis file berdasarkan nama file atau URL-nya, yang diberikan oleh url. Nilai kembali adalah tupel (jenis, penyandian) di mana jenisnya adalah Tidak ada jika jenisnya tidak dapat ditebak (sufiks yang hilang atau tidak diketahui) atau string dari bentuk 'tipe / subtipe', dapat digunakan untuk header tipe konten MIME.

encoding adalah None for no encoding atau nama program yang digunakan untuk mengkodekan (mis. kompres atau gzip). Pengkodean ini cocok untuk digunakan sebagai header Content-Encoding, bukan sebagai header Content-Transfer-Encoding. Pemetaan didorong oleh tabel. Sufiks enkode bersifat peka huruf besar-kecil; sufiks jenis pertama kali dicoba case secara sensitif, kemudian case tidak sensitif.

Argumen ketat opsional adalah bendera yang menentukan apakah daftar tipe MIME yang dikenal terbatas hanya pada tipe resmi yang terdaftar di IANA. Ketika ketat adalah Benar (default), hanya tipe IANA yang didukung; ketika ketat adalah Salah, beberapa tipe MIME yang tidak standar tetapi umum digunakan juga dikenali.

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

Anda tidak menyatakan server web apa yang Anda gunakan, tetapi Apache memiliki modul kecil yang bagus yang disebut Mime Magic yang digunakannya untuk menentukan jenis file ketika disuruh melakukannya. Itu membaca beberapa konten file dan mencoba untuk mencari tahu jenis apa itu berdasarkan karakter yang ditemukan. Dan sebagai Dave Webb Disebutkan dalam Mimetypes Modul di bawah python akan bekerja, memberikan perpanjangan berguna.

Atau, jika Anda duduk di kotak UNIX, Anda dapat menggunakan sys.popen('file -i ' + fileName, mode='r')untuk mengambil jenis MIME. Windows seharusnya memiliki perintah yang setara, tetapi saya tidak yakin apa itu.

akdom
sumber
7
Sekarang Anda bisa melakukan subprocess.check_output (['file', '-b', '--mime', filename])
Nathan Villaescusa
Sebenarnya tidak ada alasan untuk menggunakan alat eksternal ketika python-magic melakukan hal yang sama, semua dibungkus dan nyaman.
damd
4

Dalam Python 3.x dan webapp dengan url ke file yang tidak dapat memiliki ekstensi atau ekstensi palsu. Anda harus menginstal python-magic, menggunakan

pip3 install python-magic

Untuk Mac OS X, Anda juga harus menginstal libmagic menggunakan

brew install libmagic

Cuplikan kode

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)

atau Anda bisa memasukkan ukuran ke dalam bacaan

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
sumber
Apakah akan memuat seluruh file?
吴毅 凡
Tidak, ini streaming, jadi biasanya hanya beberapa byte.
Claude COULOMBE
Saya telah diedit oleh response.readline () atau response.read (128) Terima kasih!
Claude COULOMBE
3

Saya mencoba meniru perpustakaan terlebih dahulu. Jika tidak berhasil, saya menggunakan perpustakaan 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
sumber
1

Modul mimetypes hanya mengenali tipe file berdasarkan ekstensi file. Jika Anda akan mencoba memulihkan jenis file tanpa ekstensi, mimetypes tidak akan berfungsi.

Helder
sumber
3
Saya pikir itu tidak benar. Jenis MIME adalah tentang cara memberi tahu orang lain tentang format data, bukan tentang cara mengetahui sendiri format data tersebut. Jika Anda menggunakan alat yang menebak format hanya berdasarkan ekstensi dan mencetak tipe MIME maka Anda tidak dapat menggunakan alat itu jika tidak ada ekstensi file. Tetapi cara lain untuk menebak format juga dimungkinkan, misalnya, dengan memeriksa dengan parser.
erikbwork
1

Saya terkejut bahwa tidak ada yang menyebutkannya, tetapi Pygments mampu membuat tebakan yang berpendidikan tentang jenis teks pantomim, khususnya, dokumen teks.

Pygments sebenarnya adalah pustaka sintaksis Python tetapi memiliki metode yang akan membuat tebakan berpendidikan tentang mana dari 500 jenis dokumen yang didukung dokumen Anda. yaitu c ++ vs C # vs Python vs dll

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)

Keluaran:

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

Sekarang, ini tidak sempurna, tetapi jika Anda harus tahu dari 500 format dokumen yang digunakan, ini sangat berguna.

Eric McLachlan
sumber
0

Saya sudah mencoba banyak contoh tetapi dengan Django mutagen bermain bagus.

Contoh memeriksa apakah file mp3

from mutagen.mp3 import MP3, HeaderNotFoundError  

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

Kelemahannya adalah kemampuan Anda untuk memeriksa jenis file terbatas, tetapi ini merupakan cara yang bagus jika Anda ingin tidak hanya memeriksa jenis file tetapi juga untuk mengakses informasi tambahan.

Artem Bernatskyi
sumber
saya perlu memeriksa keamanan juga
Artem Bernatskyi
0

Untuk data jenis byte Array, Anda dapat menggunakan magic.from_buffer (_byte_array, mime = True)

Pengguna Super
sumber
-1

Anda dapat menggunakan modul Python imghdr .

jianpx
sumber
1
Ini bukan komentar yang bermanfaat, karena itu tidak memberikan contoh juga tidak benar-benar mengatakan bagaimana atau mengapa imghdr akan membantu di sini.
erikbwork
2
Ya aku mengerti itu. Sudah lebih dari setahun yang lalu, tetapi mungkin Anda masih dapat memperbaruinya karena masih ada orang yang mencari pertanyaan ini, seperti saya. Jika Anda butuh bantuan, Anda bisa memberi tahu saya.
erikbwork
1
Ini hanya berfungsi untuk daftar tipe gambar yang sangat terbatas. Tidak tahu tentang file teks, arsip terkompresi, format dokumen, dll.
tripleee