Skip to main content

下载和处理文件和图像

Scrapy提供可重复使用的 项目管道,用于下载附加到特定项目的文件(例如,当您抓取产品并想要在本地下载其图像时)。这些管道共享一点功能和结构(我们称之为媒体管道),但通常你要么使用文件管道或图像管道。

两个管道都实现这些功能:

  • 避免重新下载最近下载的媒体

  • 指定存储媒体的位置(文件系统目录,Amazon S3存储桶)

图像管道有一些额外的功能处理图像:

  • 将所有下载的图像转换为常用格式(JPG)和模式(RGB)

  • 缩略图生成

  • 检查图像宽度/高度,以确保它们满足最小约束

管道还保持当前正被调度下载的那些媒体URL的内部队列,并将包含相同媒体的那些响应连接到那个队列。这避免了多个项目共享时多次下载相同的媒体。

使用文件管道

典型的工作流程,当使用 FilesPipeline 时,像这样:

  1. 在“蜘蛛”中,您将抓取一个项目,并将所需的网址放入 file_urls 字段中。

  2. 该项目从蜘蛛返回并转到项目管道。

  3. 当项目到达 FilesPipeline 时,使用标准Scrapy调度程序和下载程序(这意味着调度程序和下载程序中间件被重用)来调度 file_urls 字段中的URL,但是具有较高的优先级,在其它页面被刮除之前对其进行处理。该项目在该特定流水线阶段保持“锁定”,直到文件完成下载(或由于某种原因失败)。

  4. 下载文件时,将用结果填充另一个字段(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_STOREIMAGES_STORE 可以表示Amazon S3存储桶。 Scrapy会自动将文件上传到存储桶。

例如,这是一个有效的 IMAGES_STORE 值:

IMAGES_STORE = 's3://bucket/images'

您可以修改用于存储文件的访问控制列表(ACL)策略,该策略由 FILES_STORE_S3_ACLIMAGES_STORE_S3_ACL 设置定义。缺省情况下,ACL为 private。要使文件公开可用,请使用 public-read 策略:

IMAGES_STORE_S3_ACL = 'public-read'

有关更多信息,请参阅Amazon S3开发人员指南中的 canned ACLs

用法示例

为了首先使用媒体管道,启用它

然后,如果蜘蛛使用URLs关键字(file_urlsimage_urls,分别为文件或图像管道)返回dict,管道将把结果放在相应的键(filesimages)下。

如果您更喜欢使用 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 字典键(smallbig 等)中指定的键,

  • <image_id> 是图片网址的 SHA1 hash

使用 smallbig 缩略图名称存储的图像文件示例:

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

第一个是从网站下载的完整图像。

过滤掉小图像

使用图像管道时,可以通过在 IMAGES_MIN_HEIGHTIMAGES_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。

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

ImagesPipelineFilesPipeline 的扩展,自定义字段名称并添加图像的自定义行为。

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