下载和处理文件和图像¶
Scrapy提供可重复使用的 项目管道,用于下载附加到特定项目的文件(例如,当您抓取产品并想要在本地下载其图像时)。这些管道共享一点功能和结构(我们称之为媒体管道),但通常你要么使用文件管道或图像管道。
两个管道都实现这些功能:
避免重新下载最近下载的媒体
指定存储媒体的位置(文件系统目录,Amazon S3存储桶)
图像管道有一些额外的功能处理图像:
将所有下载的图像转换为常用格式(JPG)和模式(RGB)
缩略图生成
检查图像宽度/高度,以确保它们满足最小约束
管道还保持当前正被调度下载的那些媒体URL的内部队列,并将包含相同媒体的那些响应连接到那个队列。这避免了多个项目共享时多次下载相同的媒体。
使用文件管道¶
典型的工作流程,当使用 FilesPipeline
时,像这样:
在“蜘蛛”中,您将抓取一个项目,并将所需的网址放入
file_urls
字段中。该项目从蜘蛛返回并转到项目管道。
当项目到达
FilesPipeline
时,使用标准Scrapy调度程序和下载程序(这意味着调度程序和下载程序中间件被重用)来调度file_urls
字段中的URL,但是具有较高的优先级,在其它页面被刮除之前对其进行处理。该项目在该特定流水线阶段保持“锁定”,直到文件完成下载(或由于某种原因失败)。下载文件时,将用结果填充另一个字段(
files
)。此字段将包含具有关于下载的文件的信息的例句列表,例如下载的路径,原始的抓取的URL(从file_urls
字段获取)和文件校验和。files
字段的列表中的文件将保持与原始file_urls
字段相同的顺序。如果某些文件下载失败,将记录一个错误,该文件将不会出现在files
字段中。
使用图像管道¶
使用 ImagesPipeline
很像使用 FilesPipeline
,除了使用的默认字段名称不同:您对项目的图像URL使用 image_urls
,并且它将填充关于下载的图像的信息的 images
字段。
使用 ImagesPipeline
的图像文件的优点是,您可以配置一些额外的功能,如生成缩略图和过滤的图像基于其大小。
Images Pipeline使用 Pillow 进行缩略图并将图像标准化为JPEG/RGB格式,因此您需要安装此库才能使用它。 Python Imaging Library (PIL)在大多数情况下也应该工作,但是已知会在一些设置中引起麻烦,因此我们建议使用 Pillow 而不是PIL。
启用媒体管道¶
要启用媒体管道,必须先将其添加到项目 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'
支持的存储¶
文件系统是目前唯一官方支持的存储,但也支持在 Amazon S3 中存储文件。
文件系统存储¶
文件使用其URL的 SHA1 hash 作为文件名存储。
例如,以下图片网址:
http://www.example.com/image.jpg
SHA1 hash 是谁:
3afec3b4765f8f0a07b78f98c07b83f013567a0a
将被下载并存储在以下文件中:
<IMAGES_STORE>/full/3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg
哪里:
<IMAGES_STORE>
是在Images管道的IMAGES_STORE
设置中定义的目录。full
是用于从缩略图(如果使用)分离完整图像的子目录。有关更多信息,请参阅 图像缩略图生成。
Amazon S3存储¶
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'
有关更多信息,请参阅Amazon S3开发人员指南中的 canned ACLs。
用法示例¶
为了首先使用媒体管道,启用它。
然后,如果蜘蛛使用URLs关键字(file_urls
或 image_urls
,分别为文件或图像管道)返回dict,管道将把结果放在相应的键(files
或 images
)下。
如果您更喜欢使用 Item
,请使用必要的字段定义自定义项目,如Images Pipeline的示例:
import scrapy
class MyItem(scrapy.Item):
# ... other item fields ...
image_urls = scrapy.Field()
images = scrapy.Field()
如果要对URLs键或结果键使用其他字段名称,也可以覆盖它。
对于文件管道,设置 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设置,并使用您的自定义设置。
附加功能¶
文件过期¶
Image Pipeline避免下载最近下载的文件。要调整此保留延迟,请使用 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 Pipeline将使用此格式创建每个指定大小的缩略图:
<IMAGES_STORE>/thumbs/<size_name>/<image_id>.jpg
哪里:
<size_name>
是在IMAGES_THUMBS
字典键(small
,big
等)中指定的键,<image_id>
是图片网址的 SHA1 hash
使用 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×105)或(105×200)或(200×105)的图像将被丢弃,因为至少一个维度比约束短。
默认情况下,没有大小约束,因此处理所有图像。
扩展介质管道¶
请参阅此处您可以在自定义文件管道中覆盖的方法:
-
class
scrapy.pipelines.files.
FilesPipeline
¶ -
get_media_requests
(item, info)¶ 如工作流所示,管道将获得要从项目下载的图像的URL。为此,您可以覆盖
get_media_requests()
方法,并为每个文件URL返回一个请求:def get_media_requests(self, item, info): for file_url in item['file_urls']: yield scrapy.Request(file_url)
这些请求将由流水线处理,并且当它们完成下载时,结果将作为2元素元组的列表发送到
item_completed()
方法。每个元组将包含(success, file_info_or_error)
,其中:success
是一个布尔值,如果映像已成功下载,则为True
;如果由于某种原因失败,则为False
file_info_or_error
是包含以下键(如果成功是True
)或如果有问题的 Twisted Failure 的dict。url
- 文件从中下载的网址。这是从get_media_requests()
方法返回的请求的url。path
- 存储文件的路径(相对于FILES_STORE
)checksum
- 图像内容的 MD5 hash
item_completed()
接收的元组列表保证保留从get_media_requests()
方法返回的请求的相同顺序。这里是
results
参数的典型值:[(True, {'checksum': '2b00042f7481c7b056c4b410d28f33cf', 'path': 'full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg', 'url': 'http://www.example.com/files/product1.pdf'}), (False, Failure(...))]
默认情况下,
get_media_requests()
方法返回None
,这意味着没有要下载的项目的文件。
-
item_completed
(results, item, info)¶ 当对单个项目的所有文件请求已完成(完成下载,或由于某种原因失败)时调用
FilesPipeline.item_completed()
方法。item_completed()
方法必须返回将发送到后续项目流水线阶段的输出,因此您必须返回(或删除)项目,就像在任何流水线中一样。这里是
item_completed()
方法的一个例子,其中我们将下载的文件路径(在结果中传递)存储在file_paths
项目字段中,并且如果项目不包含任何文件: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") item['file_paths'] = file_paths return item
默认情况下,
item_completed()
方法返回项目。
-
请参阅此处您可以在自定义图像管道中覆盖的方法:
-
class
scrapy.pipelines.images.
ImagesPipeline
¶ ImagesPipeline
是FilesPipeline
的扩展,自定义字段名称并添加图像的自定义行为。-
get_media_requests
(item, info)¶ 与
FilesPipeline.get_media_requests()
方法的工作方式相同,但对图像网址使用不同的字段名称。必须为每个图片网址返回一个请求。
-
item_completed
(results, item, info)¶ 当对单个项目的所有图像请求已完成(完成下载,或由于某种原因失败)时,调用
ImagesPipeline.item_completed()
方法。与
FilesPipeline.item_completed()
方法的工作方式相同,但使用不同的字段名称来存储图像下载结果。默认情况下,
item_completed()
方法返回项目。
-
自定义图像管道示例¶
下面是其方法如上所示的Images Pipeline的完整示例:
import scrapy
from scrapy.pipelines.images import ImagesPipeline
from scrapy.exceptions import DropItem
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")
item['image_paths'] = image_paths
return item