Как найти MIME-тип файла в Python?

194

Допустим, вы хотите сохранить несколько файлов где-нибудь, например, в BLOB. Допустим, вы хотите выложить эти файлы через веб-страницу, и клиент автоматически открывает нужное приложение / средство просмотра.

Предположение: браузер выясняет, какое приложение / средство просмотра использовать заголовком mime-type (content-type?) В ответе HTTP.

Исходя из этого предположения, помимо байтов файла, вы также хотите сохранить тип MIME.

Как бы вы нашли MIME-тип файла? Я в настоящее время на Mac, но это также должно работать на Windows.

Добавляет ли браузер эту информацию при публикации файла на веб-странице?

Есть ли аккуратная библиотека Python для поиска этой информации? Веб-сервис или (что еще лучше) загружаемая база данных?

Дарен Томас
источник

Ответы:

218

Метод магии питона, предложенный toivotuo, устарел. Текущий ствол Python-magic находится в Github, и, основываясь на этом файле readme, поиск MIME-типа выполняется следующим образом.

# For MIME types
import magic
mime = magic.Magic(mime=True)
mime.from_file("testdata/test.pdf") # 'application/pdf'
Саймон Циммерманн
источник
17
Спасибо за комментарий! обратите внимание, что «выше» является сложной концепцией в стеке потока, так как порядок сгруппирован по голосам и упорядочен случайным образом внутри групп. Я предполагаю, что вы ссылаетесь на ответ @ toivotuo.
Дарен Томас
1
Да, у меня не было достаточно «точек» для создания комментариев на момент написания этого ответа. Но я, вероятно, должен был написать это как комментарий, чтобы @toivotuo мог отредактировать его вопрос.
Симон Циммерманн
1
rpm -qf /usr/lib/python2.7/site-packages/magic.py -i URL: darwinsys.com/file Сводка: привязки Python для libmagic API rpm -qf / usr / bin / file -i Имя: файл URL: darwinsys.com/file python-magic из darwinsys.com/file, который поставляется с Linux. Fedora работает так, как сказал @ toivotuo. И кажется больше основного потока.
Сержиу
7
Помните, что пакет debian / ubuntu, называемый python-magic, отличается от пакета pip с тем же именем. Оба они import magicимеют несовместимое содержание. См. Stackoverflow.com/a/16203777/3189 для получения дополнительной информации.
Хэмиш Даунер
1
Как я прокомментировал ответ toivotuo, он не устарел! Вы говорите о другой библиотеке. Можете ли вы удалить или заменить это утверждение в своем ответе? В настоящее время это действительно затрудняет поиск лучшего решения.
Бодо
87

Модуль mimetypes в стандартной библиотеке будет определять / угадывать MIME-тип по расширению файла.

Если пользователи загружают файлы, сообщение HTTP будет содержать MIME-тип файла вместе с данными. Например, Django делает эти данные доступными в качестве атрибута объекта UploadedFile .

Дэйв Уэбб
источник
12
Если файлы хранятся в BLOB-файлах, как указано в вопросе, возможно, вы не знаете расширение файла.
Механическая улитка
55
Расширения файлов не являются надежным способом определения типа пантомимы.
Cerin
13
import mimetypes mimetypes.MimeTypes().guess_type(filename)[0]
Джонатан
4
в Python 3.6 это работает:mimetypes.guess_type(path_file_to_upload)[1]
JinSnow
3
Хотя @cerin прав, что расширения файлов ненадежны, я только что обнаружил, что точность python-magic(как предложено в верхнем ответе) еще ниже, что подтверждается github.com/s3tools/s3cmd/issues/198 . Так что, mimetypesкажется, лучший кандидат для меня.
17
46

Более надежный способ, чем использовать библиотеку mimetypes, - использовать пакет python-magic.

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

Это было бы эквивалентно использованию файла (1).

В Django можно также убедиться, что тип MIME совпадает с типом UploadedFile.content_type.

toivotuo
источник
2
См. Сообщение Саймона Циммермана об обновленном использовании магии питона
Дарен Томас
@DarenThomas: Как уже упоминалось в ответе Маммадори, этот ответ не устарел и не отличается от решения Саймона Циммермана. Если у вас установлена ​​файловая утилита, вы можете использовать это решение. У меня работает с файлом-5.32. В gentoo также необходимо включить USE-флаг python для файлового пакета.
Бодж
36

Это кажется очень простым

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

Пожалуйста, обратитесь Старый пост

Обновление - согласно комментарию @Garrets, в python 3 это более просто:

import mimetypes
print(mimetypes.guess_type("sample.html"))
Лаксмикант Ратнапархи
источник
4
Я не думаю, что urllib требуется в вашем примере.
BrotherJack
5
для Python 3.X замените импортный urllib запросом на импорт из urllib. А затем используйте «запрос» вместо urllib
Арджун Тхакур
1
Также работает для Python 2.7
Джей Моди
@ Оое игровое решение использует этот модуль, но является более простым.
Гаррет
11

Есть 3 разных библиотеки, которые обертывают libmagic.

2 из них доступны на pypi (поэтому установка pip будет работать):

  • filemagic
  • питон-магия

И еще один, похожий на python-magic, доступен непосредственно в последних источниках libmagic, и он, вероятно, есть в вашем дистрибутиве Linux.

В Debian пакет python-magic об этом и используется, как сказал toivotuo, и не устарел, как сказал Саймон Циммерман (IMHO).

Мне кажется, еще один вариант (автором libmagic).

Жаль, что не доступен непосредственно на Pypi.

mammadori
источник
Я добавил репо для удобства: github.com/mammadori/magic-python так , как вы можете: pip install -e git://github.com/mammadori/magic-python.git#egg=Magic_file_extensions
mammadori
10

в Python 2.6:

mime = subprocess.Popen("/usr/bin/file --mime PATH", shell=True, \
    stdout=subprocess.PIPE).communicate()[0]
apito
источник
6
В этом нет необходимости, поскольку fileкоманда в основном является оболочкой libmagic. Вы можете также использовать привязку python (python-magic), как в ответе Саймона.
Механическая улитка
6
Это зависит от операционной системы. Например, в Mac OS X у вас есть «файл», но в обычной среде нет libmagic.
rptb1
9

Обновление 2017

Нет необходимости переходить на github, он находится на PyPi под другим именем:

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

Код также может быть упрощен:

>>> import magic

>>> magic.from_file('/tmp/img_3304.jpg', mime=True)
'image/jpeg'
Гринго Суаве
источник
Вы можете сделать то же самое для JS или CSS файла?
Кумбханибхавеш
Конечно, почему нет?
Гринго Суаве
9

Привязки Python к libmagic

Все разные ответы на эту тему очень запутаны, поэтому я надеюсь дать немного большей ясности в этом обзоре различных привязок libmagic. Ранее Маммадори дал краткий ответ с перечислением доступных вариантов.

libmagic

При определении MIME-типа файлов просто вызывается инструмент выбора и вызывается fileего серверная часть libmagic. (См. Домашнюю страницу проекта .) Проект разработан в частном cvs-хранилище, но на github есть зеркало git , доступное только для чтения. .

Теперь этот инструмент, который вам понадобится, если вы хотите использовать какие-либо привязки libmagic с python, уже поставляется с собственными привязками python, которые называются file-magic. Существует не так много посвященных документаций для них, но вы всегда можете посмотреть на человек странице с-библиотеке: man libmagic. Основное использование описано в файле 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)

Помимо этого, вы также можете использовать библиотеку, создав Magicобъект, используя, magic.open(flags)как показано в файле примера .

И toivotuo, и ewr2san используют эти file-magicпривязки, включенные в fileинструмент. Они ошибочно предполагают, что используют python-magicпакет. Кажется, это указывает на то, что если оба fileи python-magicустановлены, модуль python magicссылается на первый.

питон-магия

Это библиотека, о которой говорит Саймон Циммерман в своем ответе, и которая также используется Клодом Куломбом и Гринго Суаве .

filemagic

Заметка : последний раз проект обновлялся в 2013 году!

Благодаря тому, что эта библиотека основана на одном и том же c-api, она имеет некоторое сходство с file-magicвключенной в libmagic. Это упоминается только маммадори, и никакой другой ответ не использует его.

Бодо
источник
7

Метод @toivotuo работал лучше и надежнее для меня под python3. Моя цель состояла в том, чтобы идентифицировать сжатые файлы, которые не имеют надежного расширения .gz. Я установил 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))

для сжатого файла возвращается: application / gzip; кодировка = двоичное

для распакованного txt-файла (данные iostat): text / plain; Charset = US-ASCII

для файла tar: application / x-tar; кодировка = двоичное

для файла bz2: application / x-bzip2; кодировка = двоичное

и последний, но не менее важный для меня .zip файл: application / zip; кодировка = двоичное

ewr2san
источник
7

ссылка на python 3: https://docs.python.org/3.2/library/mimetypes.html

mimetypes.guess_type (url, strict = True) Угадайте тип файла на основе его имени файла или URL-адреса, заданного url. Возвращаемое значение - кортеж (тип, кодировка), где тип - None, если тип не может быть угадан (отсутствующий или неизвестный суффикс), или строка вида «тип / подтип», используемая для заголовка типа содержимого MIME.

Кодировка - Нет для отсутствия кодировки или названия программы, используемой для кодирования (например, compress или gzip). Кодировка подходит для использования в качестве заголовка Content-Encoding, а не в качестве заголовка Content-Transfer-Encoding. Отображения основаны на таблицах. Суффиксы кодирования чувствительны к регистру; суффиксы типов сначала проверяются с учетом регистра, а затем без учета регистра.

Необязательный строгий аргумент - это флаг, указывающий, ограничен ли список известных типов MIME только официальными типами, зарегистрированными в IANA. Если для параметра strict установлено значение True (по умолчанию), поддерживаются только типы IANA; когда для параметра false установлено значение False, также распознаются некоторые дополнительные нестандартные, но часто используемые типы MIME.

import mimetypes
print(mimetypes.guess_type("sample.html"))
Отци
источник
6

Вы не указали, какой веб-сервер вы используете, но у Apache есть симпатичный маленький модуль, называемый Mime Magic, который он использует для определения типа файла, когда ему это сказано. Он читает часть содержимого файла и пытается выяснить, какой тип основан на найденных символах. И как Дэйв Уэбб Упоминается в Mimetypes Модуль под питона будет работать, если расширение удобно.

В качестве альтернативы, если вы сидите в окне UNIX, вы можете использовать, sys.popen('file -i ' + fileName, mode='r')чтобы получить MIME-тип. Windows должна иметь эквивалентную команду, но я не уверен, что это такое.

akdom
источник
7
В настоящее время вы можете просто выполнить subprocess.check_output (['file', '-b', '--mime', filename])
Nathan Villaescusa
На самом деле нет никаких оснований прибегать к использованию внешнего инструмента, когда python-magic делает то же самое, все упаковано и удобно.
Черт
4

В Python 3.x и веб-приложении с URL-адресом файла, который не может иметь расширение или поддельное расширение. Вы должны установить Python-Magic, используя

pip3 install python-magic

Для Mac OS X вы также должны установить libmagic, используя

brew install libmagic

Фрагмент кода

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)

в качестве альтернативы вы можете поместить размер в чтение

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)
Клод Куломб
источник
Будет ли загружаться весь файл?
Нет, это поток, поэтому обычно всего несколько байтов.
Клод Кулом
Я редактировал response.readline () или response.read (128) Спасибо!
Клод Куломб
3

Я сначала пробую библиотеку mimetypes. Если это не работает, я использую библиотеку 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

Модуль mimetypes просто распознает тип файла на основе расширения файла. Если вы попытаетесь восстановить тип файла без расширения, mimetypes не будет работать.

Элдер
источник
3
Я не думаю, что это правда. Тип MIME предназначен для того, чтобы рассказывать другим о формате данных, а не о том, как самостоятельно определить формат данных. Если вы используете инструмент, который угадывает формат только на основе расширения и печатает MIME-типы, вы не сможете использовать этот инструмент, если нет расширений файлов. Но возможны и другие способы угадать формат, например, с помощью парсера.
erikbwork
1

Я удивлен, что никто не упомянул об этом, но Pygments способен сделать обоснованное предположение о типе пантомимы, в частности, текстовых документов.

На самом деле Pygments - это библиотека подсветки синтаксиса Python, но в ней есть метод, позволяющий сделать обоснованное предположение о том, какой из 500 поддерживаемых типов документов является вашим документом. то есть c ++ против C # против Python против и т. д.

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)

Вывод:

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

Теперь это не идеально, но если вам нужно определить, какой из 500 форматов документов используется, это чертовски полезно.

Эрик МакЛахлан
источник
0

Я пробовал много примеров, но с Django мутаген играет хорошо.

Пример проверки наличия файлов mp3

from mutagen.mp3 import MP3, HeaderNotFoundError  

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

Недостатком является то, что ваша способность проверять типы файлов ограничена, но это отличный способ, если вы хотите не только проверить тип файла, но и получить доступ к дополнительной информации.

Артем Бернацкий
источник
мне также нужно проверить безопасность
Артем Бернацкий
0

Для данных типа байтового массива вы можете использовать magic.from_buffer (_byte_array, mime = True)

суперпользователя
источник
-1

Вы можете использовать модуль imghdr Python.

jianpx
источник
1
Это не полезный комментарий, потому что он не дает примеров и не говорит, как и почему imghdr мог бы помочь здесь.
erikbwork
2
Да, я понимаю это. Это больше года назад, но, возможно, вы все еще можете обновить его, потому что есть люди, которые ищут этот вопрос, как я. Если вам нужна помощь, вы можете сказать мне.
erikbwork
1
Это работает только для очень ограниченного списка типов изображений. Он не имеет ни малейшего представления о текстовых файлах, сжатых архивах, форматах документов и т. Д.
tripleee