Scrapy笔记08- 文件与图片

Scrapy为我们供给了可重用的item pipelines为某个特定的Item去下载文件。通常来讲你会选择应用Files Pipeline或Images Pipeline。

这两个管道都实现了:

  • 避免反复下载
  • 可以指定下载后保留的处所(文件体系目录中,Amazon S3中)

Images Pipeline为处置图片供给了额外的功效:

  • 将所有下载的图片格局转换成普通的JPG并应用RGB色彩模式
  • 生成缩略图
  • 检讨图片的宽度和高度确保它们满足最小的尺码限制

管道同时会在内部保留一个被调度下载的URL列表,然后将包括雷同媒体的相应关联到这个队列上来,从而避免了多个item同享这个媒体时反复下载。

应用Files Pipeline

一般我们会依照下面的步骤来应用文件管道:

  1. 在某个Spider中,你爬取一个item后,将相应的文件URL放入file_urls字段中
  2. item被返回以后就会转交给item pipeline
  3. 当这个item达到FilesPipeline时,在file_urls字段中的URL列表会通过尺度的Scrapy调度器和下载器来调度下载,并且优先级很高,在抓取其他页眼前就被处置。而这个item会一直在这个pipeline中被锁定,直到所有的文件下载完成。
  4. 当文件被下载完以后,成果会被赋值给另外一个files字段。这个字段包括一个关于下载文件新的字典列表,比以下载路径,源地址,文件校验码。files里面的次序和file_url次序是一致的。要是某个写文件下载出错就不会涌现在这个files中了。

应用Images Pipeline

ImagesPipelineFilesPipeline的应用差不多,不过应用的字段名不一样,image_urls保留图片URL地址,images保留下载后的图片信息。

应用ImagesPipeline的利益是你可以通过配置来供给额外的功效,比如生成文件缩略图,通过图片大小过滤须要下载的图片等。

ImagesPipeline应用Pillow来生成缩略图和转换成尺度的JPEG/RGB格局。因此你须要安装这个包,我们建议你应用Pillow而不是PIL。

应用例子

要应用媒体管道,请先在配置文件中打开它

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 同时应用图片和文件管道
ITEM_PIPELINES = {
"scrapy.pipelines.images.ImagesPipeline": 1,
"scrapy.pipelines.files.FilesPipeline": 2,
}
FILES_STORE = "/path/to/valid/dir" # 文件存储路径
IMAGES_STORE = "/path/to/valid/dir" # 图片存储路径
# 90 days of delay for files expiration
FILES_EXPIRES = 90
# 30 days of delay for images expiration
IMAGES_EXPIRES = 30
# 图片缩略图
IMAGES_THUMBS = {
"small": (50, 50),
"big": (270, 270),
}
# 图片过滤器,最小高度和宽度
IMAGES_MIN_HEIGHT = 110
IMAGES_MIN_WIDTH = 110

一个应用了缩略图的下载例子会生成以下图片:

1
2
3
<IMAGES_STORE>/full/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
<IMAGES_STORE>/thumbs/small/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg
<IMAGES_STORE>/thumbs/big/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg

然后,某个Item返回时,有file_urlsimage_urls,并且存在相应的filesimages字段

1
2
3
4
5
6
7
import scrapy

class MyItem(scrapy.Item):

# ... other item fields ...
image_urls = scrapy.Field()
images = scrapy.Field()

自定义媒体管道

如果你还须要更加庞杂的功效,想自定义下载媒体逻辑,请参考扩大媒体管道

不论是扩大FilesPipeline还是ImagesPipeline,都只需重写下面两个办法

  • get_media_requests(self, item, info),返回一个Request对象
  • item_completed(self, results, item, info),当上门的Request下载完成后回调这个办法,然后填充filesimages字段

下面是一个扩大ImagesPipeline的例子,我只取path信息,并将它赋给image_paths字段,而不是默许的images

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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