译者:OSGeo 中国
废料可重复使用 item pipelines 用于下载附加到特定项目的文件(例如,当您抓取产品并希望在本地下载其图像时)。这些管道共享一些功能和结构(我们将它们称为媒体管道),但通常您可以使用文件管道或图像管道。
两条管道都实现了以下功能:
- 避免重新下载最近下载的媒体
- 指定存储媒体的位置(文件系统目录、AmazonS3存储桶、Google云存储桶)
图像管道有一些用于处理图像的额外功能:
- 将所有下载的图像转换为通用格式(JPG)和模式(RGB)
- 缩略图生成
- 检查图像的宽度/高度以确保它们满足最小限制
这些管道还保留当前正在计划下载的媒体URL的内部队列,并将到达的包含相同媒体的响应连接到该队列。这样可以避免在多个项目共享同一媒体时多次下载同一媒体。
使用时的典型工作流 FilesPipeline
像这样:
- 在spider中,您抓取一个项目并将所需的URL放入
file_urls
字段。 - 该项从spider返回并转到项管道。
- 当项目到达
FilesPipeline
,中的URLfile_urls
使用标准的Scrapy计划程序和下载程序(这意味着计划程序和下载程序中间软件被重用)来计划下载字段,但具有更高的优先级,在其他页面被抓取之前对其进行处理。该项在特定管道阶段保持“锁定”,直到文件完成下载(或由于某种原因失败)。 - 下载文件时,另一个字段(
files
)将用结果填充。此字段将包含一个包含有关下载文件的信息的dict列表,例如下载路径、原始的scraped url(取自file_urls
字段)和文件校验和。列表中的文件files
字段将保留与原始字段相同的顺序file_urls
字段。如果某些文件下载失败,将记录一个错误,并且该文件不会出现在files
字段。
使用 ImagesPipeline
很像使用 FilesPipeline
,但使用的默认字段名不同:您使用 image_urls
对于项目的图像URL,它将填充 images
有关下载图像的信息字段。
使用 ImagesPipeline
对于图像文件,您可以配置一些额外的功能,如生成缩略图和根据图像大小过滤图像。
图像管道使用 Pillow 对于缩略图和将图像规范化为jpeg/rgb格式,因此需要安装此库才能使用它。 Python Imaging Library (PIL)在大多数情况下也应该有效,但它在某些设置中会引起问题,因此我们建议使用 Pillow 而不是皮尔。
要启用媒体管道,必须首先将其添加到项目中 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 和 Google Cloud Storage .
文件使用 SHA1 hash 文件名的URL。
例如,以下图像URL::
http://www.example.com/image.jpg
谁的 SHA1 hash
是::
3afec3b4765f8f0a07b78f98c07b83f013567a0a
将下载并存储在以下文件中::
<IMAGES_STORE>/full/3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg
在哪里?
<IMAGES_STORE>
目录是否在中定义?IMAGES_STORE
图像管道的设置。full
是一个子目录,用于从缩略图中分离完整图像(如果使用)。有关详细信息,请参阅 图像的缩略图生成 .
FILES_STORE
和 IMAGES_STORE
可以表示AmazonS3存储桶。Scrapy会自动将文件上传到bucket。
例如,这是一个有效的 IMAGES_STORE
价值:
IMAGES_STORE = 's3://buckimg'
您可以修改用于存储文件的访问控制列表(ACL)策略,该策略由 FILES_STORE_S3_ACL
和 IMAGES_STORE_S3_ACL
设置。默认情况下,acl设置为 private
. 要使文件公开,请使用 public-read
政策:
IMAGES_STORE_S3_ACL = 'public-read'
有关详细信息,请参阅 canned ACLs 在AmazonS3开发者指南中。
因为下流的东西 boto
/ botocore
在内部,您还可以使用其他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)
FILES_STORE
和 IMAGES_STORE
可以表示一个谷歌云存储桶。Scrapy会自动将文件上传到bucket。(需要 google-cloud-storage )
例如,这些是有效的 IMAGES_STORE
和 GCS_PROJECT_ID
设置::
IMAGES_STORE = 'gs://buckimg/'
GCS_PROJECT_ID = 'project_id'
有关身份验证的信息,请参见 documentation .
您可以修改用于存储文件的访问控制列表(ACL)策略,该策略由 FILES_STORE_GCS_ACL
和 IMAGES_STORE_GCS_ACL
设置。默认情况下,acl设置为 ''
(空字符串)这意味着云存储将bucket的默认对象acl应用于该对象。要使文件公开,请使用 publicRead
政策:
IMAGES_STORE_GCS_ACL = 'publicRead'
有关详细信息,请参阅 Predefined ACLs 在谷歌云平台开发者指南中。
为了首先使用媒体管道, enable it .
然后,如果spider返回带有urls键的dict( file_urls
或 image_urls
,对于文件或图像管道,管道将把结果放在各自的键下。( files
或 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,并且您希望有自定义图像URL字段,那么您可以定义设置mypipeline图像URL字段,并且将使用自定义设置。
图像管道避免下载最近下载的文件。要调整此保留延迟,请使用 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天。
如果您有子类filespine的管道,并且希望对其进行不同的设置,则可以设置以大写类名开头的设置键。例如,给定名为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>
是 SHA1 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
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)
这些请求将由管道处理,下载完成后,结果将发送到 item_completed()
方法,作为2元素元组的列表。每个元组将包含 (success, file_info_or_error)
在哪里?
success
是一个布尔值,它是True
如果图像下载成功或False
如果因为某种原因失败了file_info_or_error
是包含以下键的dict(如果成功是True
或A Twisted Failure 如果有问题的话。url
-从中下载文件的URL。这是从get_media_requests()
方法。path
-路径(相对于FILES_STORE
)文件的存储位置checksum
-A 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()
方法,但对图像URL使用不同的字段名。
必须返回每个图像URL的请求。
item_completed(results, item, info)
这个 ImagesPipeline.item_completed()
当一个项目的所有图像请求都已完成时(要么已完成下载,要么由于某种原因失败),将调用方法。
工作方式与 FilesPipeline.item_completed()
方法,但使用不同的字段名存储图像下载结果。
默认情况下, item_completed()
方法返回项。
下面是一个完整的图像管道示例,其方法如上所示:
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