Определяем расширение файла в Python

Потребовалось сейчас сделать быструю проверку того, что тип скачиваемого программой файла — картинка в формате webp, а если это не она, то не качать ее вовсе, ну или хотя бы не полностью.

Самый быстрый способ — сделать HEAD запрос и проверить content-type, например, с помощью питоновской библиотеки mimetypes:


import requests
import mimetypes

r = requests.head("https://.../image.webp")
file_ext = mimetypes.guess_extension(r.headers.get("content-type"), strict=False)

if file_ext == "webp":
    pass

Можно ли точно полагаться на ответ сервера? В целом, нет, ведь даже если этот заголовок с виду корректен, то в тело ответа сервер может запихнуть что угодно. Однако, можно отсеивать очевидно ненужные варианты типа text/plain или чего-то подобного.

А еще бывает так, что нужный файл отдается с не тем типом контента. Например, в моем случае нужное хранилище AWS S3 грешило тем, что отдавало файл картинки с заголовком binary/octet-stream.

А еще HEAD запрос может не поддерживаться веб-сервером.

И что делать-то? Будем использовать обертку над libmagic, библиотеку python-magic. Она позволит нам по небольшому чанку данных узнать mime тип получаемого контента.


import os
import magic
import requests
import mimetypes

local_filename = "/local/file/name.webp"

r = requests.get("https://.../image.webp", stream=True)
f = open(local_filename, "wb")

for chunk in r.iter_content(1024):
    mime = magic.from_buffer(chunk, mime=True)
    file_ext = mimetypes.guess_extension(mime, strict=False)

    if new_file_ext != "webp":
        f.close()
        os.remove(local_filename)
        break

    f.write(chunk)
else:
    f.close()
    # Тут уже что-то можем делать с полученным файлом.


Вроде, выглядит норм. Ну, еще обработку ошибок добавить бы не помешало, да.

Но вот с точки зрения работы с сетью есть некоторые сомнения, что в случае вызова break, requests реально считает только 1 кб данных. Беглое гугление скорее усугубило мои сомнения. Надо иметь это в виду и как-нибудь на досуге реально протестировать.

В общем, все.

P.S. Если mimetypes не смогла определить расширение файла webp по типу контента image/webp, то его стоит добавить вручную в один из файлов mime.types вашей системы. Например, для Ubuntu это файл /etc/mime.types, в который надо добавить строку:


image/webp    webp

Другие файлики, откуда mimetypes может загружать себе данные, прописаны в самой библиотеке в массиве knownfiles:


knownfiles = [
    "/etc/mime.types",
    "/etc/httpd/mime.types",                    # Mac OS X
    "/etc/httpd/conf/mime.types",               # Apache
    "/etc/apache/mime.types",                   # Apache 1
    "/etc/apache2/mime.types",                  # Apache 2
    "/usr/local/etc/httpd/conf/mime.types",
    "/usr/local/lib/netscape/mime.types",
    "/usr/local/etc/httpd/conf/mime.types",     # Apache 1.2
    "/usr/local/etc/mime.types",                # Apache 1.3
]

Поделиться
Отправить
 162   9 мес   Python
Популярное