Làm thế nào để tìm loại mime của một tập tin trong python?


193

Giả sử bạn muốn lưu một loạt các tệp ở đâu đó, ví dụ như trong BLOB. Giả sử bạn muốn xử lý các tệp này thông qua một trang web và để máy khách tự động mở ứng dụng / trình xem chính xác.

Giả định: Trình duyệt chỉ ra ứng dụng / trình xem nào được sử dụng bởi tiêu đề loại mime (loại nội dung?) Trong phản hồi HTTP.

Dựa trên giả định đó, ngoài các byte của tệp, bạn cũng muốn lưu loại MIME.

Làm thế nào bạn sẽ tìm thấy loại MIME của một tập tin? Tôi hiện đang sử dụng máy Mac, nhưng ứng dụng này cũng hoạt động trên Windows.

Trình duyệt có thêm thông tin này khi đăng tệp lên trang web không?

Có một thư viện python gọn gàng để tìm thông tin này? WebService hoặc (thậm chí tốt hơn) cơ sở dữ liệu có thể tải xuống?

Câu trả lời:


217

Phương pháp ma thuật python được đề xuất bởi to Pivotuo đã lỗi thời. Thân cây hiện tại của Python-magic đang ở Github và dựa trên readme ở đó, việc tìm loại MIME, được thực hiện như thế này.

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

17
cảm ơn vì nhận xét xin lưu ý rằng "ở trên" là một khái niệm khó khăn trong stackoverflow, vì thứ tự được nhóm theo phiếu bầu và được sắp xếp ngẫu nhiên trong các nhóm. Tôi đoán bạn tham khảo câu trả lời của @ to Pivotuo.
Daren Thomas

1
Yeh, tôi không có đủ "điểm" để tạo bình luận tại thời điểm viết bài trả lời này. Nhưng tôi có lẽ nên viết nó như một bình luận, để @to Pivotuo có thể chỉnh sửa câu hỏi của anh ấy.
Simon Zimmermann

1
rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL: darwinsys.com/file Tóm tắt: Các ràng buộc Python cho API libmagic URL: darwinsys.com/file python-magic từ darwinsys.com/file và đi kèm với Linux Fedora hoạt động như @ to Pivotuo nói. Và dường như nhiều luồng chính hơn.
Sérgio

7
Coi chừng gói debian / ub Ubuntu gọi là python-magic khác với gói pip cùng tên. Cả hai đều import magiccó nội dung không tương thích. Xem stackoverflow.com/a/16203777/3189 để biết thêm.
Hamish Downer

1
Như tôi đã nhận xét về câu trả lời của to Pivotuo, nó không bị lỗi thời! Bạn đang nói về một thư viện khác. Bạn có thể vui lòng loại bỏ hoặc thay thế tuyên bố đó trong câu trả lời của bạn? Nó hiện đang làm cho việc tìm giải pháp tốt nhất thực sự khó khăn.
Bodo

86

Các kiểu MIME mô-đun trong thư viện chuẩn sẽ xác định / đoán kiểu MIME từ một phần mở rộng tập tin.

Nếu người dùng đang tải lên các tệp, bài đăng HTTP sẽ chứa loại MIME của tệp cùng với dữ liệu. Ví dụ, Django cung cấp dữ liệu này dưới dạng một thuộc tính của đối tượng UploadedFile .


12
Nếu các tệp được lưu trữ trong BLOB, như được chỉ định trong câu hỏi, bạn có thể không biết phần mở rộng tệp.
Ốc cơ khí

55
Phần mở rộng tệp không phải là một cách đáng tin cậy để xác định loại mime.
Cerin

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

4
trong python 3.6, công việc này:mimetypes.guess_type(path_file_to_upload)[1]
JinSnow

3
Mặc dù @cerin nói đúng rằng các phần mở rộng tệp không đáng tin cậy, tôi vừa phát hiện ra rằng độ chính xác của python-magic(như được đề xuất trong câu trả lời trên cùng) thậm chí còn thấp hơn, như được xác nhận bởi github.com/s3tools/s3cmd/issues/198 . Vì vậy, mimetypesdường như một ứng cử viên tốt hơn cho tôi.
dan Khánh

46

Cách đáng tin cậy hơn là sử dụng thư viện mimetypes sẽ là sử dụng gói ma thuật python.

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

Điều này sẽ tương đương với việc sử dụng tập tin (1).

Trên Django, người ta cũng có thể đảm bảo rằng loại MIME khớp với loại của UploadedFile.content_type.


2
Xem bài đăng của Simon Zimmermann để biết cách sử dụng ma thuật trăn cập nhật
Daren Thomas

@DarenThomas: Như đã đề cập trong câu trả lời của mammador, câu trả lời này không lỗi thời và khác biệt với giải pháp của Simon Zimmermann. Nếu bạn đã cài đặt tiện ích tập tin, có lẽ bạn có thể sử dụng giải pháp này. Nó hoạt động với tôi với tập tin-5.32. Trên gentoo, bạn cũng phải bật cờ USE python cho gói tệp.
Bodo

35

Điều này dường như là rất dễ dàng

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

Vui lòng tham khảo bài cũ

Cập nhật - Theo nhận xét @Garrets, trong python 3 đơn giản hơn:

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

4
Tôi không nghĩ rằng urllib là bắt buộc trong ví dụ của bạn.
BrotherJack

5
cho Python 3.X thay thế nhập urllib bằng từ yêu cầu nhập urllib. Và sau đó sử dụng "yêu cầu" thay vì urllib
Arjun Thakur

1
Cũng hoạt động cho python 2.7
Jay Modi

Giải pháp của @ oetzi sử dụng mô-đun này, nhưng đơn giản hơn.
Garrett

11

Có 3 thư viện khác nhau kết thúc libmagic.

2 trong số chúng có sẵn trên pypi (vì vậy cài đặt pip sẽ hoạt động):

  • hiếu thảo
  • trăn-ma thuật

Và một thứ khác, tương tự như python-magic có sẵn trực tiếp trong các nguồn libmagic mới nhất, và nó là thứ bạn có thể có trong bản phân phối linux của mình.

Trong Debian, gói python-magic nói về cái này và nó được sử dụng như to Pivotuo đã nói và nó không bị lỗi thời như Simon Zimmermann đã nói (IMHO).

Nó dường như với tôi một mất (của tác giả ban đầu của libmagic).

Quá xấu là không có sẵn trực tiếp trên pypi.


Tôi đã thêm một repo để thuận tiện: github.com/mammadori/magic-python theo cách bạn có thể: pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
mammadori

10

trong trăn 2.6:

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

6
Điều này là không cần thiết, vì filevề cơ bản lệnh chỉ là một trình bao bọc xung quanh libmagic. Bạn cũng có thể chỉ sử dụng liên kết trăn (ma thuật trăn), như trong câu trả lời của Simon.
Ốc cơ khí

6
Điều đó phụ thuộc vào hệ điều hành. Ví dụ, trên Mac OS X, bạn có "tệp" nhưng không libmagic trong môi trường bình thường.
rptb1

9

Cập nhật 2017

Không cần phải đi đến github, đó là trên PyPi dưới một tên khác:

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

Mã cũng có thể được đơn giản hóa:

>>> import magic

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

bạn có thể làm tương tự cho tập tin js hoặc css không?
kumbhanibhavesh

Chắc chắn, tại sao không ??
Gringo Suave

8

Python ràng buộc với libmagic

Tất cả các câu trả lời khác nhau về chủ đề này đều rất khó hiểu, vì vậy tôi hy vọng sẽ làm rõ hơn một chút với tổng quan này về các ràng buộc khác nhau của libmagic. Trước đây mammadori đã đưa ra một câu trả lời ngắn liệt kê các tùy chọn có sẵn.

thất vọng

Khi xác định loại tệp mime, công cụ lựa chọn được gọi đơn giản filevà back-end của nó được gọi libmagic. (Xem trang chủ Dự án .) Dự án được phát triển trong kho lưu trữ cvs riêng, nhưng có một gương git chỉ đọc trên github .

Bây giờ công cụ này, mà bạn sẽ cần nếu bạn muốn sử dụng bất kỳ ràng buộc libmagic nào với python, đã đi kèm với các ràng buộc python riêng của nó được gọi file-magic. Không có nhiều tài liệu dành riêng cho họ, nhưng bạn luôn có thể xem trang người đàn ông của thư viện c : man libmagic. Cách sử dụng cơ bản được mô tả trong tệp 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)

Ngoài ra, bạn cũng có thể sử dụng thư viện bằng cách tạo một Magicđối tượng bằng cách sử dụng magic.open(flags)như trong tệp ví dụ .

Cả to Pivotuo và ewr2san đều sử dụng các file-magicràng buộc này có trong filecông cụ. Họ lầm tưởng, họ đang sử dụng python-magicgói. Điều này dường như chỉ ra rằng, nếu cả hai filepython-magic được cài đặt, mô-đun python magicđề cập đến mô-đun cũ.

trăn-ma thuật

Đây là thư viện mà Simon Zimmermann nói về câu trả lời của mình và cũng được Claude COULOMBE sử dụng cũng như Gringo Suave sử dụng .

hiếu thảo

Ghi chú : Dự án này được cập nhật lần cuối vào năm 2013!

Do được dựa trên cùng một c-api, thư viện này có một số điểm tương đồng với file-magicbao gồm trong libmagic. Nó chỉ được đề cập bởi mammadori và không có câu trả lời nào khác sử dụng nó.


7

Phương pháp của @to Pivotuo hoạt động tốt nhất và đáng tin cậy nhất đối với tôi theo python3. Mục tiêu của tôi là xác định các tệp được nén mà không có phần mở rộng .gz đáng tin cậy. Tôi đã cài đặt python3-ma thuật.

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

đối với một tệp được nén, nó trả về: application / gzip; bộ ký tự = nhị phân

đối với tệp txt đã giải nén (dữ liệu i bổ sung): text / plain; bộ ký tự = us-ascii

cho một tập tin tar: application / x-tar; bộ ký tự = nhị phân

đối với tệp bz2: application / x-bzip2; bộ ký tự = nhị phân

và cuối cùng nhưng không kém phần quan trọng đối với tôi một tệp .zip: application / zip; bộ ký tự = nhị phân


6

Bạn đã không nói rõ máy chủ web nào bạn đang sử dụng, nhưng Apache có một mô-đun nhỏ xinh xắn tên là Mime Magic mà nó sử dụng để xác định loại tệp khi được yêu cầu làm như vậy. Nó đọc một số nội dung của tệp và cố gắng tìm ra loại nào dựa trên các ký tự được tìm thấy. Và như Dave Webb đề cập các mimetypes Mô-đun dưới python sẽ làm việc, cung cấp một phần mở rộng rất thuận tiện.

Ngoài ra, nếu bạn đang ngồi trên một hộp UNIX, bạn có thể sử dụng sys.popen('file -i ' + fileName, mode='r')để lấy loại MIME. Windows nên có một lệnh tương đương, nhưng tôi không chắc nó là gì.


7
Ngày nay, bạn chỉ có thể thực hiện quy trình con.checkDefput (['tệp', '-b', '--mime', tên tệp])
Nathan Villaescusa

Thực sự không có lý do gì để sử dụng một công cụ bên ngoài khi python-Magic làm điều tương tự, tất cả được bao bọc và ấm cúng.
chết tiệt

6

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

mimetypes.guess_type (url, rict = True) Đoán loại tệp dựa trên tên tệp hoặc URL của nó, được cung cấp bởi url. Giá trị trả về là một tuple (loại, mã hóa) trong đó loại là Không nếu loại không thể đoán được (hậu tố bị thiếu hoặc không xác định) hoặc một chuỗi có dạng 'loại / loại phụ', có thể sử dụng cho tiêu đề loại nội dung MIME.

mã hóa là Không có mã hóa hoặc tên của chương trình được sử dụng để mã hóa (ví dụ: nén hoặc gzip). Mã hóa phù hợp để sử dụng làm tiêu đề Mã hóa nội dung, không phải là tiêu đề Mã hóa chuyển nội dung. Các ánh xạ được điều khiển bảng. Hậu tố mã hóa là trường hợp nhạy cảm; hậu tố loại đầu tiên được thử trường hợp nhạy cảm, sau đó trường hợp không nhạy cảm.

Đối số chặt chẽ tùy chọn là một cờ xác định xem danh sách các loại MIME đã biết có bị giới hạn chỉ với các loại chính thức được đăng ký với IANA hay không. Khi nghiêm ngặt là True (mặc định), chỉ các loại IANA được hỗ trợ; khi nghiêm ngặt là Sai, một số loại MIME không chuẩn nhưng thường được sử dụng cũng được công nhận.

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

4

Trong Python 3.x và webapp có url đến tệp không thể có tiện ích mở rộng hoặc tiện ích mở rộng giả. Bạn nên cài đặt python-Magic, sử dụng

pip3 install python-magic

Đối với Mac OS X, bạn cũng nên cài đặt libmagic bằng cách sử dụng

brew install libmagic

Đoạn mã

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)

Ngoài ra, bạn có thể đặt một kích thước vào đọc

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)

Nó sẽ được tải toàn bộ tập tin?
吴毅 凡 17/03/2017

Không, đó là một luồng, vì vậy thông thường chỉ là vài byte.
Claude COULOMBE 17/03/2017

Tôi đã chỉnh sửa bằng answer.readline () hoặc answer.read (128) Cảm ơn bạn!
Claude COULOMBE

2

Tôi thử thư viện mimetypes đầu tiên. Nếu nó không hoạt động, tôi sử dụng libary python-ma thuật thay thế.

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

Mô-đun mimetypes chỉ nhận ra một loại tệp dựa trên phần mở rộng tệp. Nếu bạn sẽ cố gắng khôi phục một loại tệp của một tệp mà không có phần mở rộng, các mimetypes sẽ không hoạt động.


3
Tôi không nghĩ đó là sự thật. Kiểu MIME là về cách nói với người khác về định dạng dữ liệu, chứ không phải về cách tự tìm ra định dạng dữ liệu. Nếu bạn sử dụng một công cụ đoán định dạng chỉ dựa trên tiện ích mở rộng và in ra các loại MIME thì bạn không thể sử dụng công cụ đó nếu không có tiện ích mở rộng tệp. Nhưng các cách khác để đoán định dạng cũng có thể, ví dụ, bằng cách kiểm tra với trình phân tích cú pháp.
erikbwork 17/12/13

0

Tôi đã thử rất nhiều ví dụ nhưng với Django mutagen chơi độc đáo.

Ví dụ kiểm tra nếu tập tin là mp3

from mutagen.mp3 import MP3, HeaderNotFoundError  

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

Nhược điểm là khả năng kiểm tra các loại tệp của bạn bị hạn chế, nhưng đó là một cách tuyệt vời nếu bạn không chỉ muốn kiểm tra loại tệp mà còn truy cập thêm thông tin.


tôi cũng cần kiểm tra an ninh
Artem Bernatskyi


0

Đối với dữ liệu kiểu byte Array, bạn có thể sử dụng magic.from_buffer (_byte_array, mime = True)


0

Tôi ngạc nhiên khi không ai nhắc đến nó ngoài Pygments có thể đưa ra một phỏng đoán có giáo dục về loại văn bản, đặc biệt là các tài liệu văn bản.

Pygments thực sự là một thư viện tô sáng cú pháp Python nhưng có một phương thức sẽ đưa ra phỏng đoán có giáo dục về 500 loại tài liệu được hỗ trợ mà tài liệu của bạn là. tức là c ++ vs C # vs Python vs v.v

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)

Đầu ra:

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

Bây giờ, nó không hoàn hảo, nhưng nếu bạn cần biết 500 định dạng tài liệu nào đang được sử dụng, thì điều này khá hữu ích.


-1

bạn có thể sử dụng mô-đun Python imghdr .


1
Đây không phải là một nhận xét hữu ích, bởi vì nó không đưa ra ví dụ cũng như không thực sự nói làm thế nào hoặc tại sao imghdr sẽ giúp đỡ ở đây.
erikbwork 17/12/13

2
Vâng, tôi hiểu điều đó. Đã hơn một năm trước nhưng có lẽ bạn vẫn có thể cập nhật nó vì vẫn có người tìm kiếm câu hỏi này, như tôi. Nếu bạn cần giúp đỡ, bạn có thể nói với tôi.
erikbwork

1
Nó chỉ hoạt động cho một danh sách rất hạn chế các loại hình ảnh. Nó không có ý tưởng về các tệp văn bản, lưu trữ nén, định dạng tài liệu, v.v.
tripleee
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.