Scrapy提供了一些可重用的Item Pipeline
来下载与 Item
相关的文件。例如,当在抓取某个商品的信息时,可能也想把它的图片下载下来。这些Pipeline
的功能和结构都有些类似(我们把它们叫做Media Pipeline
),但最常用的是Images Pipeline
和Files Pipeline
。
这两种Pipeleine
都有如下特点:
Images Pipeline
对于处理图片还有一些额外的功能:
这些Pipeline
同时在内部维持一个正被调度以待下载的媒体url的队列,并且把包含相同媒体的响应与队列关联起来。这样可以避免当多个Item
都包含同一个媒体时这个媒体不会被下载多次。
使用Files Pipeline
的一般工作流程是这样的:
Item
,把需要下载的文件的URL放到file_urls
字段中去。Item
从爬虫中返回,并到达Item Pipeline
。Item
到达FilesPipeline
时,file_urls
字段中的url会通过标准的Scrapy调度器和下载器进行调度和下载,不过这种调度的优先级较高,会在其他页面被抓取之前就处理这些url。处理的过程中,这个Item
会被这个pipeline
加上锁,直到文件下载完毕或者由于某些原因下载失败。files
。这个字段包含了一个字典的列表,里面是下载下来的文件的信息,例如,下载后放置的路径、是从哪个url抓取的(从file_urls
字段获得此信息)以及文件检验和。files
字段列表文件顺序和file_urls
字段顺序是一致的。如果某个文件下载失败,那么错误记录到日志里,而文件不会出现在files
字段。ImagesPipeline
的使用方法和FilesPipeline
很大程度上是相同的,只是一些默认的字段名称不同:用image_urls
字段存放需要下载的图片的地址,下载完毕后图片信息填充到images
字段中。
使用ImagesPipeline
来处理专门图片文件有一些好处是你可以额外地设置一些函数来生成缩略图或者基于图片的尺寸来对图片进行过滤。
ImagesPipeline
使用Pillow库来生成缩略图以及把图片标准化为JPEG/RGB格式,在使用之前需要先安装。PIL在在多数情况下也是可以使用的,不过在某些设置中会导致一些问题。因此建议还要使用Pillow来代替。
要使用媒体管道,需要先启用它:
首先把它加到工程的ITEM_PIPELINES
设置项中,对于Images Pipeline
,可以这样写:
ITEM_PIPELINES = {‘scrapy.pipelines.images.ImagesPipeline’: 1}
而对于Files Pipeline
,要这样写:
ITEM_PIPELINES = {‘scrapy.pipelines.files.FilesPipeline’: 1}
可以同时使用这两个Pipeline。
然后需要给下载下来的文件配置一个有效的存储位置,否则这个pipeline仍然不能使用,即使已经在ITEM_PIPELINES
里添加了它。对于Files Pipeline
是:
FILES_STORE = ‘/path/to/valid/dir’
对于Images Pipeline
是:
IMAGES_STORE = ‘/path/to/valid/dir’
根据以上两个步骤启用了媒体管道之后,如果爬虫返回的是字典,其中有个键为file_urls
或者image_urls
,相应的pipeline就会以把结果分别存储在files
或者images
键中。
如果爬虫的输出采用的是Item
,那就需要在定义的item中添加一些必要的字段,像这样:
import scrapy
class MyItem(scrapy.Item):
# ... other item fields ...
image_urls = scrapy.Field()
images = scrapy.Field()
这些必要的字段的名字也可以由设置项来修改,image_urls
这个字段可以由IMAGES_URLS_FIELD
来设置,images
这个字段可以由IMAGES_RESULT_FIELD
来设置。
至于文件的存储方式,目前官方支持的只有本地文件系统这一种方法,但也同时支持在Amazon S3上存储文件。
在本地文件系统上,文件名是用相应的url的SHA1哈希得来的,比如这个图片的url是http://www.example.com/image.jpg
,哈希之后对应的结果是
3afec3b4765f8f0a07b78f98c07b83f013567a0a
,它会被下载下来然后存储到:
<IMAGES_STORE>/full/3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg
其中,<IMAGES_STORE>
是在启用Images Pipeline
时设置的IMAGES_STORE
选项代表的目录。而full
是用来区分完整的图片和缩略图而产生的子目录(如果生成了缩略图的话)。
这些媒体管道不会下载最近已经下载过的文件,除非文件已经过期,而这个过期时间就是由FILES_EXPIRE
或IMAGES_EXPIRE
来设置的,单位为天。如:
# 90 days of delay for files expiration
FILES_EXPIRES = 90
# 30 days of delay for images expiration
IMAGES_EXPIRES = 30
Images Pipeline
可以自动地为图片生成缩略图,如果要启用这个功能,需要把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>
则是图片的url对应的哈希值。
分别以small
和big
为名字生成的缩略示例如下所示:
<IMAGES_STORE>/full/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
<IMAGES_STORE>/thumbs/small/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
<IMAGES_STORE>/thumbs/big/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
第一行是完整的图片,从网站上下载的原始图片。
使用Images Pipeline
时,设置了IMAGES_MIN_HEIGHT
和IMAGES_MIN_WIDTH
的值后,可以丢弃尺寸过小的图片。例如:
IMAGES_MIN_HEIGHT = 110
IMAGES_MIN_WIDTH = 110
要注意的是,这种尺寸约束不会影响缩略图的生成。默认情况下,没有图片的尺寸约束,所有的图片都会被处理。
如果还要实现更加复杂的功能,就需要自己实现Pipeline的逻辑,可以参考Scrapy文档。