Скачивание и обработка файлов и изображений
Scrapy предоставляет переиспользуемые конвейеры элементов для загрузки файлов, прикрепленных к определённому элементу (например, когда вы очищаете продукты, а также хотите загрузить их изображения локально). Данные конвейеры имеют общие функциональные возможности и структуру (мы называем их конвейерами мультимедиа), но обычно вы будете использовать конвейер файлов или конвейер изображений.
Оба конвейера реализуют данные функции:
Избегайте повторной загрузки медиафайлов, которые были загружены недавно
Указание места для хранения мультимедиа (каталог файловой системы, FTP-сервер, корзина Amazon S3, корзина Google Cloud Storage)
В конвейере изображений есть несколько дополнительных функций для обработки изображений:
Преобразовать все загруженные изображения в общий формат (JPG) и режим (RGB)
Создание эскизов
Проверить ширину и высоту изображений, чтобы убедиться, что они соответствуют минимальным ограничениям
Конвейеры также хранят внутреннюю очередь тех URL-адресов мультимедиа, которые в настоящее время планируются для загрузки, и подключают к этой очереди те ответы, которые поступают, содержащие тот же носитель. Это позволяет избежать загрузки одного и того же медиафайла более одного раза, если он используется несколькими объектами.
Использование файлового конвейера
Типичный рабочий процесс при использовании FilesPipeline
выглядит следующим образом:
В Spider вы очищаете элемент и помещаете желаемые URL-адреса в поле
file_urls
.Элемент возвращается от паука и попадает в конвейер элемента.
Когда элемент достигает
FilesPipeline
, URL-адреса в полеfile_urls
планируются для загрузки с использованием стандартного планировщика и загрузчика Scrapy (что означает, что промежуточное ПО планировщика и загрузчика повторно используется), но с более высоким приоритетом, обрабатывая их до очистки других страниц. Элемент остаётся «заблокированным» на этом конкретном этапе конвейера до тех пор, пока файлы не загрузятся (или не завершатся ошибкой по какой-либо причине).Когда файлы будут загружены, другое поле (
files
) будет заполнено результатами. Это поле будет содержать список dicts с информацией о загруженных файлах, такой как загруженный путь, исходный очищенный URL (взятый из поляfile_urls
), контрольная сумма файла и статус файла. Файлы в списке поляfiles
сохранят тот же порядок, что и исходное полеfile_urls
. Если не удалось загрузить какой-либо файл, в журнал будет записана ошибка, и файл не будет отображаться в полеfiles
.
Использование конвейера изображений
Использование ImagesPipeline
во многом похоже на использование FilesPipeline
, за исключением того, что используемые по умолчанию имена полей отличаются: вы используете image_urls
для URL-адресов изображений элемента, и он заполняет поле images
для информации о загруженных изображениях.
Преимущество использования ImagesPipeline
для файлов изображений заключается в том, что вы можете настроить некоторые дополнительные функции, такие как создание эскизов и фильтрация изображений на основе их размера.
Для конвейера изображений требуется Pillow 4.0.0 или более поздней версии. Он используется для миниатюр и нормализации изображений в формат JPEG/RGB.
Включение вашего медиа-конвейера
Чтобы включить конвейер мультимедиа, сначала необходимо добавить его в настройку проекта ITEM_PIPELINES
.
Для конвейера изображений используйте:
ITEM_PIPELINES = {'scrapy.pipelines.images.ImagesPipeline': 1}
Для файлового конвейера используйте:
ITEM_PIPELINES = {'scrapy.pipelines.files.FilesPipeline': 1}
Примечание
Вы также можете использовать конвейер файлов и изображений одновременно.
Затем настраивает параметр целевого хранилища на допустимое значение, которое будет использоваться для хранения загруженных изображений. В противном случае конвейер останется отключенным, даже если вы включает его в настройку ITEM_PIPELINES
.
Для конвейера файлов устанавливает параметр FILES_STORE
:
FILES_STORE = '/path/to/valid/dir'
Для конвейера изображений устанавливает параметр IMAGES_STORE
:
IMAGES_STORE = '/path/to/valid/dir'
Именование файлов
Именование файлов по умолчанию
По умолчанию файлы хранятся с использованием SHA-1 хэша их URL-адресов для имён файлов.
Например, следующий URL-адрес изображения:
http://www.example.com/image.jpg
Чей SHA-1 хэш
следующий:
3afec3b4765f8f0a07b78f98c07b83f013567a0a
Будет загружено и сохранено с использованием выбранного вами методе хранилища и следующего имени файла:
3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg
Пользовательское именование файлов
Вы можете использовать другое вычисленное имя файла для сохраненных файлов. Например, классификация изображения путём включения мета в имя файла.
Настраивает имена файлов, переопределив метод file_path
вашего конвейера мультимедиа.
Например, конвейер изображений с URL-адресом изображения:
http://www.example.com/product/images/large/front/0000000004166
Может быть преобразовано в имя файла с сокращенным хешем и перспективой front
:
00b08510e4_front.jpg
Переопределив file_path
вот так:
import hashlib
from os.path import splitext
def file_path(self, request, response=None, info=None, *, item=None):
image_url_hash = hashlib.shake_256(request.url.encode()).hexdigest(5)
image_perspective = request.url.split('/')[-2]
image_filename = f'{image_url_hash}_{image_perspective}.jpg'
return image_filename
Предупреждение
Если ваша настраиваемая схема имён файлов опирается на метаданные, которые могут различаться в зависимости от очистки, это может привести к неожиданной повторной загрузке существующих носителей с использованием новых имён файлов.
Например, если в вашей пользовательской схеме имён файлов используется название продукта, а сайт меняет название продукта между циклами очистки, Scrapy повторно загрузит тот же носитель, используя обновленные имена файлов.
Дополнительные сведения о методе file_path
см. в разделе Расширение медиа-конвейеров.
Поддерживаемое хранилище
Хранилище файловой системы
Хранилище файловой системы сохранит файлы по следующему пути:
<IMAGES_STORE>/full/<FILE_NAME>
Где:
<IMAGES_STORE>
— это каталог, определённый в настройкеIMAGES_STORE
для конвейера изображений.full
— это подкаталог для отделения полных изображений от эскизов (если они используются). Для получения дополнительной информации см. Создание эскизов изображений.<FILE_NAME>
— это имя файла, присвоенное файлу. Для получения дополнительной информации см. Именование файлов.
Хранилище FTP-сервера
Добавлено в версии 2.0.
FILES_STORE
и IMAGES_STORE
могут указывать на FTP-сервер. Scrapy автоматически загрузит файлы на сервер.
FILES_STORE
и IMAGES_STORE
следует записать в одной из следующих форм:
ftp://username:password@address:port/path
ftp://address:port/path
Если username
и password
не указаны, они берутся из настроек FTP_USER
и FTP_PASSWORD
соответственно.
FTP поддерживает два разных режима подключения: активный и пассивный. Scrapy по умолчанию использует пассивный режим подключения. Чтобы вместо этого использовать активный режим подключения, устанавливает для параметра FEED_STORAGE_FTP_ACTIVE
значение True
.
Хранилище Amazon S3
Если установлен botocore >= 1.4.87, FILES_STORE
и IMAGES_STORE
могут представлять корзину Amazon S3. Scrapy автоматически загрузит файлы в корзину.
Например, это допустимое значение IMAGES_STORE
:
IMAGES_STORE = 's3://bucket/images'
Вы можете изменить политику списка управления доступом (ACL), используемую для сохраненных файлов, которая определяется параметрами FILES_STORE_S3_ACL
и IMAGES_STORE_S3_ACL
. По умолчанию для ACL задано значение private
. Чтобы сделать файлы общедоступными, используйте политику public-read
:
IMAGES_STORE_S3_ACL = 'public-read'
Дополнительные сведения см. в разделе canned ACLs
в Руководстве разработчика Amazon S3.
Вы также можете использовать другие хранилища типа S3. Такие хранилища, как Minio или s3.scality. Все, что вам нужно сделать, это установить параметр конечной точки в настройках Scrapy:
AWS_ENDPOINT_URL = 'http://minio.example.com:9000'
При самостоятельном размещении вы также можете почувствовать необходимость не использовать SSL и не проверять SSL-соединение:
AWS_USE_SSL = False # or True (None by default)
AWS_VERIFY = False # or True (None by default)
Облачное хранилище Google
FILES_STORE
и IMAGES_STORE
могут представлять корзину Google Cloud Storage. Scrapy автоматически загрузит файлы в корзину. (требуется Google Cloud Storage)
Например, это допустимые настройки IMAGES_STORE
и GCS_PROJECT_ID
:
IMAGES_STORE = 'gs://bucket/images/'
GCS_PROJECT_ID = 'project_id'
Для получения информации об аутентификации см. данной документации.
Вы можете изменить политику списка управления доступом (ACL), используемую для сохраненных файлов, которая определяется параметрами FILES_STORE_GCS_ACL
и IMAGES_STORE_GCS_ACL
. По умолчанию для ACL задано значение ''
(пустая строка), что означает, что Cloud Storage применяет к объекту ACL объекта по умолчанию для сегмента. Чтобы сделать файлы общедоступными, используйте политику publicRead
:
IMAGES_STORE_GCS_ACL = 'publicRead'
Дополнительные сведения см. в разделе Предопределённые ACL
в Руководстве разработчика Google Cloud Platform.
Пример использования
Чтобы использовать конвейер мультимедиа, сначала включите его.
Затем, если паук возвращает объект элемента с полем URL-адресов (file_urls
или image_urls
для конвейера файлов или изображений соответственно), конвейер поместит результаты в соответствующее поле (files
или images
).
При использовании типов элемента, для которого заранее определены поля, необходимо определить как поле URL-адресов, так и поле результатов. Например, при использовании конвейера изображений элементы должны определять как поле image_urls
, так и поле images
. Например, используя класс Item
:
import scrapy
class MyItem(scrapy.Item):
# ... other item fields ...
image_urls = scrapy.Field()
images = scrapy.Field()
Если вы хотите использовать другое имя поля для ключа URL-адресов или для ключа результатов, его также можно переопределить.
Для конвейера файлов устанавливает параметры FILES_URLS_FIELD
и/или FILES_RESULT_FIELD
:
FILES_URLS_FIELD = 'field_name_for_your_files_urls'
FILES_RESULT_FIELD = 'field_name_for_your_processed_files'
Для конвейера изображений устанавливает параметры IMAGES_URLS_FIELD
и/или IMAGES_RESULT_FIELD
:
IMAGES_URLS_FIELD = 'field_name_for_your_images_urls'
IMAGES_RESULT_FIELD = 'field_name_for_your_processed_images'
Если вам нужно что-то более сложное и вы хотите переопределить настраиваемое поведение конвейера, см. Расширение медиа-конвейеров.
Если у вас есть несколько конвейеров изображений, унаследованных от ImagePipeline, и вы хотите иметь разные настройки в разных конвейерах, вы можете установить ключи настройки, которым предшествует прописное имя вашего класса конвейера. Например. если ваш конвейер называется MyPipeline и вы хотите иметь собственный IMAGES_URLS_FIELD, вы определяете параметр MYPIPELINE_IMAGES_URLS_FIELD, и будут использоваться ваши пользовательские настройки.
Дополнительные возможности
Срок действия файла
Конвейер изображений избегает загрузки файлов, которые были загружены недавно. Чтобы настроить эту задержку хранения, используйте параметр FILES_EXPIRES
(или IMAGES_EXPIRES
, в случае конвейера изображений), который указывает задержку в количестве дней:
# 120 days of delay for files expiration
FILES_EXPIRES = 120
# 30 days of delay for images expiration
IMAGES_EXPIRES = 30
Значение по умолчанию для обеих настроек — 90 дней.
Если у вас есть конвейер, который является подклассом FilesPipeline, и вы хотите иметь для него другие настройки, вы можете установить ключи настройки, которым предшествует имя класса в верхнем регистре. Например. учитывая класс конвейера MyPipeline, вы можете установить ключ настройки:
MYPIPELINE_FILES_EXPIRES = 180
а для конвейерного класса MyPipeline будет установлено время истечения 180.
Время последнего изменения из файла используется для определения возраста файла в днях, который затем сравнивается с установленным сроком действия, чтобы определить, истек ли срок действия файла.
Создание эскизов изображений
Конвейер изображений может автоматически создавать эскизы загруженных изображений.
Чтобы использовать эту функцию, вы должны установить IMAGES_THUMBS
в словарь, где ключи — это имена миниатюр, а значения — их размеры.
Например:
IMAGES_THUMBS = {
'small': (50, 50),
'big': (270, 270),
}
Когда вы используете эту функцию, конвейер изображений будет создавать миниатюры каждого указанного размера в этом формате:
<IMAGES_STORE>/thumbs/<size_name>/<image_id>.jpg
Где:
<size_name>
— это тот, который указан в ключах словаряIMAGES_THUMBS
(small
,big
и т. Д.)<image_id>
— это SHA-1 hash URL-адреса изображения
Пример файлов изображений, хранящихся с именами эскизов small
и big
:
<IMAGES_STORE>/full/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
<IMAGES_STORE>/thumbs/small/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
<IMAGES_STORE>/thumbs/big/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
Первый — это полный образ, скачанный с сайта.
Фильтрация небольших изображений
При использовании конвейера изображений вы можете отбрасывать слишком маленькие изображения, указав минимально допустимый размер в настройках IMAGES_MIN_HEIGHT
и IMAGES_MIN_WIDTH
.
Например:
IMAGES_MIN_HEIGHT = 110
IMAGES_MIN_WIDTH = 110
Примечание
Ограничения размера вообще не влияют на создание эскизов.
Можно установить только одно ограничение размера или оба. При установке обоих из них будут сохранены только изображения, удовлетворяющие обоим минимальным размерам. В приведённом выше примере изображения размеров (105 x 105), (105 x 200) или (200 x 105) будут отброшены, потому что по крайней мере одно измерение короче ограничения.
По умолчанию ограничений по размеру нет, поэтому обрабатываются все изображения.
Разрешение перенаправления
По умолчанию конвейеры мультимедиа игнорируют перенаправления, т. е. перенаправление HTTP на URL-запрос мультимедийного файла будет означать, что загрузка мультимедиа считается неудачной.
Для обработки перенаправления мультимедиа устанавливает для этого параметра значение True
:
MEDIA_ALLOW_REDIRECTS = True
Расширение медиа-конвейеров
См. здесь методы, которые можно переопределить в пользовательском конвейере файлов:
- class scrapy.pipelines.files.FilesPipeline
- file_path(self, request, response=None, info=None, *, item=None)
Данный метод вызывается один раз для каждого загруженного элемента. Он возвращает путь загрузки файла, происходящего из указанного
response
.Помимо
response
, данный метод получает исходныеrequest
,info
иitem
Вы можете переопределить данный метод, чтобы настроить путь загрузки каждого файла.
Например, если URL-адреса файлов заканчиваются как обычные пути (например,
https://example.com/a/b/c/foo.png
), вы можете использовать следующий подход для загрузки всех файлов в папкуfiles
с их исходными именами (например,files/foo.png
):import os from urllib.parse import urlparse from scrapy.pipelines.files import FilesPipeline class MyFilesPipeline(FilesPipeline): def file_path(self, request, response=None, info=None, *, item=None): return 'files/' + os.path.basename(urlparse(request.url).path)
Точно так же вы можете использовать
item
для определения пути к файлу на основе некоторого свойства элемента.По умолчанию метод
file_path()
возвращаетfull/<request URL hash>.<extension>
.Добавлено в версии 2.4: Параметр item.
- get_media_requests(item, info)
Как видно из рабочего процесса, конвейер получит URL-адреса изображений для загрузки из элемента. Для этого вы можете переопределить метод
get_media_requests()
и возвращает запрос для каждого URL-адреса файла:from itemadapter import ItemAdapter def get_media_requests(self, item, info): adapter = ItemAdapter(item) for file_url in adapter['file_urls']: yield scrapy.Request(file_url)
Данные запросы будут обрабатываться конвейером, и по завершении загрузки результаты будут отправлены методу
item_completed()
в виде списка двухэлементных кортежей. Каждый кортеж будет содержать(success, file_info_or_error)
, где:success
— это логическое значениеTrue
, если изображение было загружено успешно, илиFalse
, если по какой-то причине произошёл сбойfile_info_or_error
— это словарь, содержащий следующие ключи (в случае успехаTrue
) илиFailure
, если возникла проблема.url
— URL-адрес, с которого был скачан файл. Это URL-адрес запроса, возвращённого методомget_media_requests()
.path
— путь (относительноFILES_STORE
), где хранился файлchecksum
— MD5 хэш содержимого изображенияstatus
— индикация состояния файла.Добавлено в версии 2.2.
Это может быть одно из следующих:
downloaded
— файл скачан.uptodate
— файл не был загружен, поскольку он был загружен недавно, согласно политике истечения срока действия файла.cached
— файл уже был запланирован для загрузки другим элементом, использующим тот же файл.
Список кортежей, полученных
item_completed()
, гарантированно сохранит тот же порядок запросов, возвращаемых методомget_media_requests()
.Вот типичное значение аргумента
results
:[(True, {'checksum': '2b00042f7481c7b056c4b410d28f33cf', 'path': 'full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg', 'url': 'http://www.example.com/files/product1.pdf', 'status': 'downloaded'}), (False, Failure(...))]
По умолчанию метод
get_media_requests()
возвращаетNone
, что означает, что для элемента нет файлов для загрузки.
- item_completed(results, item, info)
Метод
FilesPipeline.item_completed()
вызывается, когда все файловые запросы для одного элемента завершены (либо загрузка завершена, либо по какой-то причине не удалось).Метод
item_completed()
должен возвращать выходные данные, которые будут отправлены на последующие этапы конвейера элементов, поэтому вы должны возвращает (или отбросить) элемент, как и в любом конвейере.Вот пример метода
item_completed()
, в котором мы сохраняем загруженные пути к файлам (переданные в результатах) в поле элементаfile_paths
и отбрасываем элемент, если он не содержит файлов:from itemadapter import ItemAdapter from scrapy.exceptions import DropItem def item_completed(self, results, item, info): file_paths = [x['path'] for ok, x in results if ok] if not file_paths: raise DropItem("Item contains no files") adapter = ItemAdapter(item) adapter['file_paths'] = file_paths return item
По умолчанию метод
item_completed()
возвращает элемент.
См. здесь методы, которые можно переопределить в настраиваемом конвейере изображений:
- class scrapy.pipelines.images.ImagesPipeline
ImagesPipeline
является расширениемFilesPipeline
, настраивая имена полей и добавляя настраиваемое поведение для изображений.- file_path(self, request, response=None, info=None, *, item=None)
Данный метод вызывается один раз для каждого загруженного элемента. Он возвращает путь загрузки файла, происходящего из указанного
response
.Помимо
response
, данный метод получает исходныеrequest
,info
иitem
Вы можете переопределить данный метод, чтобы настроить путь загрузки каждого файла.
Например, если URL-адреса файлов заканчиваются как обычные пути (например,
https://example.com/a/b/c/foo.png
), вы можете использовать следующий подход для загрузки всех файлов в папкуfiles
с их исходными именами (например,files/foo.png
):import os from urllib.parse import urlparse from scrapy.pipelines.images import ImagesPipeline class MyImagesPipeline(ImagesPipeline): def file_path(self, request, response=None, info=None, *, item=None): return 'files/' + os.path.basename(urlparse(request.url).path)
Точно так же вы можете использовать
item
для определения пути к файлу на основе некоторого свойства элемента.По умолчанию метод
file_path()
возвращаетfull/<request URL hash>.<extension>
.Добавлено в версии 2.4: Параметр item.
- get_media_requests(item, info)
Работает так же, как метод
FilesPipeline.get_media_requests()
, но использует другое имя поля для URL-адресов изображений.Должен возвращать запрос для каждого URL изображения.
- item_completed(results, item, info)
Метод
ImagesPipeline.item_completed()
вызывается, когда все запросы изображений для одного элемента завершены (либо загрузка завершена, либо по какой-либо причине произошла ошибка).Работает так же, как метод
FilesPipeline.item_completed()
, но использует другие имена полей для хранения результатов загрузки изображений.По умолчанию метод
item_completed()
возвращает элемент.
Пример конвейера пользовательских изображений
Вот полный пример конвейера изображений, методы которого приведены выше:
import scrapy
from itemadapter import ItemAdapter
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline
class MyImagesPipeline(ImagesPipeline):
def get_media_requests(self, item, info):
for image_url in item['image_urls']:
yield scrapy.Request(image_url)
def item_completed(self, results, item, info):
image_paths = [x['path'] for ok, x in results if ok]
if not image_paths:
raise DropItem("Item contains no images")
adapter = ItemAdapter(item)
adapter['image_paths'] = image_paths
return item
Чтобы включить пользовательский компонент конвейера мультимедиа, необходимо добавить путь импорта его класса в параметр ITEM_PIPELINES
, как в следующем примере:
ITEM_PIPELINES = {
'myproject.pipelines.MyImagesPipeline': 300
}