рекомендации

пятница, 9 июля 2021 г.

Парсинг аудио, видео и изображений из интернета с помощью Python


Наша статья - это отрывок из книги Ричарда Лоусона «Web Scraping with Python». Эта книга содержит пошаговые инструкции по использованию методов программирования Python для этичного парсинга веб-страниц.

Распространенной практикой парсинга является загрузка, хранение и дальнейшая обработка медиаконтента (не веб-страниц или файлов данных). Они могут включать изображения, аудио и видео. Чтобы хранить контент локально (или в такой службе, как S3) и делать это правильно, нам нужно знать тип медиа, и этого недостаточно, чтобы доверять расширению файла в URL-адресе. Следовательно, мы должны знать, как загрузить и правильно представить тип мультимедиа на основе информации с веб-сервера.

Еще одна распространенная задача - создание миниатюр изображений, видео или даже страницы веб-сайта. Мы рассмотрим несколько методов создания эскизов и скриншотов страниц веб-сайта. Часто они используются на новом веб-сайте в качестве миниатюрных ссылок на скопированные файлы, которые хранятся локально.

Наконец, часто бывает необходимо иметь возможность перекодировать медиафайлы, например, преобразовывать видео в формат MP4 или изменять скорость передачи данных или разрешение видео. Другой сценарий - извлечь из видеофайла только звук. Мы не будем рассматривать перекодирование видео, но мы скопируем звук в формате MP3 из файла MP4 с помощью ffmpeg. По аналогии можно легко перекодировать видео с помощью ffmpeg.

Загрузка медиаконтента из интернета

Загрузка мультимедийного контента из интернета - это простой процесс: используйте Requests или другую библиотеку и загрузите его так же, как и HTML-контент.

В модуле urls.py в папке util есть класс с именем URLUtility. Этот класс обрабатывает несколько сценариев, описанных в этой главе, с загрузкой и анализом URL-адресов. Мы будем использовать этот класс в этом и некоторых других сценариях. Убедитесь, что папка модулей находится в вашем пути Python. Кроме того, пример этого сценария находится в файле 04/01_download_image.py.

Вот как мы приступаем к сценарию:

1. Класс URLUtility может загружать контент по URL-адресу. Код в файле сценария следующий:

import const from util.urls import URLUtility util = URLUtility(const.ApodEclipseImage()) print(len(util.data))

1. При запуске вы увидите следующий вывод:

Reading URL: https://apod.nasa.gov/apod/image/1709/BT5643s.jpg Read 171014 bytes 171014

В примере читается 171014 байт данных.

Как это работает

URL-адрес определяется как константа const.ApodEclipseImage() в модуле const:

def ApodEclipseImage(): return "https://apod.nasa.gov/apod/image/1709/BT5643s.jpg"

Конструктор класса URLUtility имеет следующую реализацию:

def __init__(self, url, readNow=True): """ Construct the object, parse the URL, and download now if specified""" self._url = url self._response = None self._parsed = urlparse(url) if readNow: self.read()

Конструктор сохраняет URL-адрес, анализирует его и загружает файл с помощью метода read(). Ниже приведен код метода read():

def read(self): self._response = urllib.request.urlopen(self._url) self._data = self._response.read()

Эта функция использует urlopen для получения ответа от объекта, а затем читает поток и сохраняет его как свойство объекта. Затем эти данные можно получить с помощью свойства data:

@property def data(self): self.ensure_response() return self._data

Затем код просто сообщает о длине этих данных, 171014.

Есть еще кое-что

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

Разбор URL-адреса с помощью urllib для получения имени файла

При загрузке контента с URL-адреса мы часто хотим сохранить его в файле. Часто бывает достаточно сохранить файл в файле с именем, указанным в URL-адресе. Но URL-адрес состоит из ряда фрагментов, поэтому как мы можем найти фактическое имя файла из URL-адреса, особенно если после имени файла часто бывает много параметров?

Мы снова будем использовать класс URLUtility для этой задачи. Файл с кодом для этого сценария - 04/02_parse_url.py.

Как это сделать

Запустите файл сценария с помощью интерпретатора Python. Будет запущен следующий код:

util = URLUtility(const.ApodEclipseImage()) print(util.filename_without_ext) This results in the following output: Reading URL: https://apod.nasa.gov/apod/image/1709/BT5643s.jpg Read 171014 bytes The filename is: BT5643s

Как это работает

В конструкторе URLUtility есть вызов urlib.parse.urlparse. Следующий пример демонстрирует интерактивное использование функции:

>>> parsed = urlparse(const.ApodEclipseImage()) >>> parsed ParseResult(scheme='https', netloc='apod.nasa.gov', path='/apod/image/1709/BT5643s.jpg', params='', query='', fragment='')

Объект ParseResult содержит различные композитные элементы URL-адреса. Элемент path содержит путь и имя файла. Вызов свойства .filename_without_ext возвращает только имя файла без расширения:

@property def filename_without_ext(self): filename = os.path.splitext(os.path.basename(self._parsed.path))[0] return filename

Вызов os.path.basename возвращает только часть имени файла в пути (включая расширение). os.path.splittext() затем разделяет имя файла и расширение, и функция возвращает первый элемент этого кортежа/списка (имя файла).

Есть еще кое-что

Может показаться странным, что этот вызов не возвращает также расширение как часть имени файла. Это связано с тем, что мы не можем предположить, что полученный контент действительно соответствует предполагаемому типу из расширения. Лучше определить это, используя заголовки, возвращаемые веб-сервером. Это наш следующий сценарий.

Определение типа контента для URL

При выполнении запросов GET для содержимого с веб-сервера сервер возвращает несколько заголовков, один из которых идентифицирует тип содержимого с точки зрения веб-сервера. В этом сценарии мы учимся использовать это, чтобы определять, что веб-сервер считает типом контента.

Мы снова используем класс URLUtility. Код сценария находится в 04/03_determine_content_type_from_response.py.

Как это сделать

Действуем следующим образом:

1. Запустите сценарий. Он содержит следующий код:

util = URLUtility(const.ApodEclipseImage()) print("The content type is: " + util.contenttype)

1. Со следующим результатом:

Reading URL: https://apod.nasa.gov/apod/image/1709/BT5643s.jpg Read 171014 bytes The content type is: image/jpeg

Как это работает

Свойство .contentype реализовано следующим образом:

@property def contenttype(self): self.ensure_response() return self._response.headers['content-type']

Свойство .headers объекта _response представляет собой класс заголовков, подобный словарю. Ключ типа содержимого будет извлекать тип содержимого, указанный сервером. Этот вызов метода sure_response() просто обеспечивает выполнение функции .read ().

Есть еще кое-что

Заголовки ответа содержат большой объем информации. Если мы более внимательно посмотрим на свойство заголовков ответа, мы увидим, что возвращаются следующие заголовки:

>>> response = urllib.request.urlopen(const.ApodEclipseImage()) >>> for header in response.headers: print(header) Date Server Last-Modified ETag Accept-Ranges Content-Length Connection Content-Type Strict-Transport-Security

И мы можем видеть значения для каждого из этих заголовков.

>>> for header in response.headers: print(header + " ==> " + response.headers[header]) Date ==> Tue, 26 Sep 2017 19:31:41 GMT Server ==> WebServer/1.0 Last-Modified ==> Thu, 31 Aug 2017 20:26:32 GMT ETag ==> "547bb44-29c06-5581275ce2b86" Accept-Ranges ==> bytes Content-Length ==> 171014 Connection ==> close Content-Type ==> image/jpeg Strict-Transport-Security ==> max-age=31536000; includeSubDomains

Многие из них мы не будем рассматривать в этой статье, но полезно знать, что они существуют.

Определение расширения файла по типу содержимого

Хорошей практикой является использование заголовка типа содержимого для определения типа содержимого и определения расширения, которое следует использовать для хранения содержимого в виде файла.

Мы снова используем созданный нами объект URLUtility. Сценарий - 04/04_determine_file_extension_from_contenttype.py) :.

Как это сделать

Продолжите, запустив скрипт. Расширение для типа мультимедиа можно найти с помощью свойства .extension:

util = URLUtility(const.ApodEclipseImage()) print("Filename from content-type: " + util.extension_from_contenttype) print("Filename from url: " + util.extension_from_url) This results in the following output: Reading URL: https://apod.nasa.gov/apod/image/1709/BT5643s.jpg Read 171014 bytes Filename from content-type: .jpg Filename from url: .jpg

Этот код сообщает как расширение, определенное на основе типа файла, так и на основе URL-адреса. Они могут быть разными, но в данном случае они одинаковы.

Как это работает

Ниже представлена ​​реализация свойства .extension_from_contenttype:

@property def extension_from_contenttype(self): self.ensure_response() map = const.ContentTypeToExtensions() if self.contenttype in map: return map[self.contenttype] return None

Первая строка гарантирует, что мы прочитали ответ от URL. Затем функция использует словарь Python, определенный в модуле const, который содержит словарь типов содержимого для расширения:

def ContentTypeToExtensions(): return { "image/jpeg": ".jpg", "image/jpg": ".jpg", "image/png": ".png" }

Если тип содержимого находится в словаре, будет возвращено соответствующее значение. В противном случае возвращается None. Обратите внимание на соответствующее свойство .extension_from_url:

@property def extension_from_url(self): ext = os.path.splitext(os.path.basename(self._parsed.path))[1] return ext

При этом используется тот же метод, что и в свойстве .filename для анализа URL-адреса, но вместо этого возвращается элемент [1], который представляет расширение вместо базового имени файла.

Подводя итог, мы обсудили, насколько эффективно мы можем парсить аудио, видео и изображения из Интернета с помощью Python.

Комментариев нет:

Отправить комментарий