Определяем расширение файла в 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
]