💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
# 下载和处理文件和图像 > 译者:[OSGeo 中国](https://www.osgeo.cn/) 废料可重复使用 [item pipelines](item-pipeline.html) 用于下载附加到特定项目的文件(例如,当您抓取产品并希望在本地下载其图像时)。这些管道共享一些功能和结构(我们将它们称为媒体管道),但通常您可以使用文件管道或图像管道。 两条管道都实现了以下功能: * 避免重新下载最近下载的媒体 * 指定存储媒体的位置(文件系统目录、AmazonS3存储桶、Google云存储桶) 图像管道有一些用于处理图像的额外功能: * 将所有下载的图像转换为通用格式(JPG)和模式(RGB) * 缩略图生成 * 检查图像的宽度/高度以确保它们满足最小限制 这些管道还保留当前正在计划下载的媒体URL的内部队列,并将到达的包含相同媒体的响应连接到该队列。这样可以避免在多个项目共享同一媒体时多次下载同一媒体。 ## 使用文件管道 使用时的典型工作流 `FilesPipeline` 像这样: 1. 在spider中,您抓取一个项目并将所需的URL放入 `file_urls` 字段。 2. 该项从spider返回并转到项管道。 3. 当项目到达 `FilesPipeline` ,中的URL `file_urls` 使用标准的Scrapy计划程序和下载程序(这意味着计划程序和下载程序中间软件被重用)来计划下载字段,但具有更高的优先级,在其他页面被抓取之前对其进行处理。该项在特定管道阶段保持“锁定”,直到文件完成下载(或由于某种原因失败)。 4. 下载文件时,另一个字段( `files` )将用结果填充。此字段将包含一个包含有关下载文件的信息的dict列表,例如下载路径、原始的scraped url(取自 `file_urls` 字段)和文件校验和。列表中的文件 `files` 字段将保留与原始字段相同的顺序 `file_urls` 字段。如果某些文件下载失败,将记录一个错误,并且该文件不会出现在 `files` 字段。 ## 使用图像管道 使用 [`ImagesPipeline`](#scrapy.pipelines.images.ImagesPipeline "scrapy.pipelines.images.ImagesPipeline") 很像使用 `FilesPipeline` ,但使用的默认字段名不同:您使用 `image_urls` 对于项目的图像URL,它将填充 `images` 有关下载图像的信息字段。 使用 [`ImagesPipeline`](#scrapy.pipelines.images.ImagesPipeline "scrapy.pipelines.images.ImagesPipeline") 对于图像文件,您可以配置一些额外的功能,如生成缩略图和根据图像大小过滤图像。 图像管道使用 [Pillow](https://github.com/python-pillow/Pillow) 对于缩略图和将图像规范化为jpeg/rgb格式,因此需要安装此库才能使用它。 [Python Imaging Library](http://www.pythonware.com/products/pil/) (PIL)在大多数情况下也应该有效,但它在某些设置中会引起问题,因此我们建议使用 [Pillow](https://github.com/python-pillow/Pillow) 而不是皮尔。 ## 启用媒体管道 要启用媒体管道,必须首先将其添加到项目中 [`ITEM_PIPELINES`](settings.html#std:setting-ITEM_PIPELINES) 设置。 对于图像管道,请使用: ```py ITEM_PIPELINES = {'scrapy.pipelines.images.ImagesPipeline': 1} ``` 对于文件管道,请使用: ```py ITEM_PIPELINES = {'scrapy.pipelines.files.FilesPipeline': 1} ``` 注解 您还可以同时使用文件和图像管道。 然后,将目标存储设置配置为用于存储下载的图像的有效值。否则,管道将保持禁用状态,即使将其包含在 [`ITEM_PIPELINES`](settings.html#std:setting-ITEM_PIPELINES) 设置。 对于文件管道,设置 [`FILES_STORE`](#std:setting-FILES_STORE) 设置: ```py FILES_STORE = '/path/to/valid/dir' ``` 对于图像管道,设置 [`IMAGES_STORE`](#std:setting-IMAGES_STORE) 设置: ```py IMAGES_STORE = '/path/to/valid/dir' ``` ## 支持的存储 文件系统目前是唯一官方支持的存储,但也支持将文件存储在 [Amazon S3](https://aws.amazon.com/s3/) 和 [Google Cloud Storage](https://cloud.google.com/storage/) . ### 文件系统存储 文件使用 [SHA1 hash](https://en.wikipedia.org/wiki/SHA_hash_functions) 文件名的URL。 例如,以下图像URL:: ```py http://www.example.com/image.jpg ``` 谁的 `SHA1 hash` 是:: ```py 3afec3b4765f8f0a07b78f98c07b83f013567a0a ``` 将下载并存储在以下文件中:: ```py <IMAGES_STORE>/full/3afec3b4765f8f0a07b78f98c07b83f013567a0a.jpg ``` 在哪里? * `&lt;IMAGES_STORE&gt;` 目录是否在中定义? [`IMAGES_STORE`](#std:setting-IMAGES_STORE) 图像管道的设置。 * `full` 是一个子目录,用于从缩略图中分离完整图像(如果使用)。有关详细信息,请参阅 [图像的缩略图生成](#topics-images-thumbnails) . ### Amazon S3存储 [`FILES_STORE`](#std:setting-FILES_STORE) 和 [`IMAGES_STORE`](#std:setting-IMAGES_STORE) 可以表示AmazonS3存储桶。Scrapy会自动将文件上传到bucket。 例如,这是一个有效的 [`IMAGES_STORE`](#std:setting-IMAGES_STORE) 价值: ```py IMAGES_STORE = 's3://buckimg' ``` 您可以修改用于存储文件的访问控制列表(ACL)策略,该策略由 [`FILES_STORE_S3_ACL`](#std:setting-FILES_STORE_S3_ACL) 和 [`IMAGES_STORE_S3_ACL`](#std:setting-IMAGES_STORE_S3_ACL) 设置。默认情况下,acl设置为 `private` . 要使文件公开,请使用 `public-read` 政策: ```py IMAGES_STORE_S3_ACL = 'public-read' ``` 有关详细信息,请参阅 [canned ACLs](https://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl) 在AmazonS3开发者指南中。 因为下流的东西 `boto` / `botocore` 在内部,您还可以使用其他S3,如存储。像自我托管这样的存储 [Minio](https://github.com/minio/minio) 或 [s3.scality](https://s3.scality.com/) . 您所需要做的就是在Scrapy设置中设置端点选项: ```py AWS_ENDPOINT_URL = 'http://minio.example.com:9000' ``` 对于自托管,您可能觉得不需要使用SSL,也不需要验证SSL连接:: ```py AWS_USE_SSL = False # or True (None by default) AWS_VERIFY = False # or True (None by default) ``` ### 谷歌云存储 [`FILES_STORE`](#std:setting-FILES_STORE) 和 [`IMAGES_STORE`](#std:setting-IMAGES_STORE) 可以表示一个谷歌云存储桶。Scrapy会自动将文件上传到bucket。(需要 [google-cloud-storage](https://cloud.google.com/storage/docs/reference/libraries#client-libraries-install-python) ) 例如,这些是有效的 [`IMAGES_STORE`](#std:setting-IMAGES_STORE) 和 [`GCS_PROJECT_ID`](#std:setting-GCS_PROJECT_ID) 设置:: ```py IMAGES_STORE = 'gs://buckimg/' GCS_PROJECT_ID = 'project_id' ``` 有关身份验证的信息,请参见 [documentation](https://cloud.google.com/docs/authentication/production) . 您可以修改用于存储文件的访问控制列表(ACL)策略,该策略由 [`FILES_STORE_GCS_ACL`](#std:setting-FILES_STORE_GCS_ACL) 和 [`IMAGES_STORE_GCS_ACL`](#std:setting-IMAGES_STORE_GCS_ACL) 设置。默认情况下,acl设置为 `''` (空字符串)这意味着云存储将bucket的默认对象acl应用于该对象。要使文件公开,请使用 `publicRead` 政策: ```py IMAGES_STORE_GCS_ACL = 'publicRead' ``` 有关详细信息,请参阅 [Predefined ACLs](https://cloud.google.com/storage/docs/access-control/lists#predefined-acl) 在谷歌云平台开发者指南中。 ## 使用实例 为了首先使用媒体管道, [enable it](#topics-media-pipeline-enabling) . 然后,如果spider返回带有urls键的dict( `file_urls` 或 `image_urls` ,对于文件或图像管道,管道将把结果放在各自的键下。( `files` 或 `images` ) 如果您喜欢使用 [`Item`](items.html#scrapy.item.Item "scrapy.item.Item") ,然后使用必要的字段定义自定义项,如本示例中的图像管道: ```py import scrapy class MyItem(scrapy.Item): # ... other item fields ... image_urls = scrapy.Field() images = scrapy.Field() ``` 如果要对URL键或结果键使用其他字段名,也可以重写它。 对于文件管道,设置 [`FILES_URLS_FIELD`](#std:setting-FILES_URLS_FIELD) 和/或 [`FILES_RESULT_FIELD`](#std:setting-FILES_RESULT_FIELD) 设置:: ```py FILES_URLS_FIELD = 'field_name_for_your_files_urls' FILES_RESULT_FIELD = 'field_name_for_your_processed_files' ``` 对于图像管道,设置 [`IMAGES_URLS_FIELD`](#std:setting-IMAGES_URLS_FIELD) 和/或 [`IMAGES_RESULT_FIELD`](#std:setting-IMAGES_RESULT_FIELD) 设置:: ```py IMAGES_URLS_FIELD = 'field_name_for_your_images_urls' IMAGES_RESULT_FIELD = 'field_name_for_your_processed_images' ``` 如果您需要更复杂的内容,并且想要覆盖自定义管道行为,请参见 [扩展媒体管道](#topics-media-pipeline-override) . 如果有多个图像管道继承自ImagePipeline,并且希望在不同的管道中具有不同的设置,则可以设置以管道类的大写名称开头的设置键。例如,如果您的管道名为mypipeline,并且您希望有自定义图像URL字段,那么您可以定义设置mypipeline图像URL字段,并且将使用自定义设置。 ## 其他功能 ### 文件过期 图像管道避免下载最近下载的文件。要调整此保留延迟,请使用 [`FILES_EXPIRES`](#std:setting-FILES_EXPIRES) 设置(或) [`IMAGES_EXPIRES`](#std:setting-IMAGES_EXPIRES) ,对于图像管道),指定延迟天数: ```py # 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`](#std:setting-IMAGES_THUMBS) 到一个字典,其中键是缩略图名称,值是它们的尺寸。 例如:: ```py IMAGES_THUMBS = { 'small': (50, 50), 'big': (270, 270), } ``` 使用此功能时,图像管道将使用以下格式创建每个指定大小的缩略图: ```py <IMAGES_STORE>/thumbs/<size_name>/<image_id>.jpg ``` 在哪里? * `&lt;size_name&gt;` 是在 [`IMAGES_THUMBS`](#std:setting-IMAGES_THUMBS) 字典键( `small` , `big` 等) * `&lt;image_id&gt;` 是 [SHA1 hash](https://en.wikipedia.org/wiki/SHA_hash_functions) 图像URL的 存储图像文件的示例 `small` 和 `big` 缩略图名称: ```py <IMAGES_STORE>/full/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg <IMAGES_STORE>/thumbs/small/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg <IMAGES_STORE>/thumbs/big/63bbfea82b8880ed33cdb762aa11fab722a90a24.jpg ``` 第一个是从网站下载的完整图像。 ### 过滤掉小图像 使用图像管道时,可以删除过小的图像,方法是在 [`IMAGES_MIN_HEIGHT`](#std:setting-IMAGES_MIN_HEIGHT) 和 [`IMAGES_MIN_WIDTH`](#std:setting-IMAGES_MIN_WIDTH) 设置。 例如:: ```py IMAGES_MIN_HEIGHT = 110 IMAGES_MIN_WIDTH = 110 ``` 注解 大小约束根本不影响缩略图的生成。 可以只设置一个大小约束或同时设置两个大小约束。当同时设置这两种尺寸时,将只保存满足这两种最小尺寸的图像。对于上面的示例,大小为(105 x 105)或(105 x 200)或(200 x 105)的图像都将被删除,因为至少有一个维度比约束短。 默认情况下,没有大小约束,因此所有图像都会被处理。 ### 允许重定向 默认情况下,媒体管道忽略重定向,即HTTP重定向到媒体文件URL请求将意味着媒体下载失败。 要处理媒体重定向,请将此设置设置为 `True` :: ```py MEDIA_ALLOW_REDIRECTS = True ``` ## 扩展媒体管道 请参见以下自定义文件管道中可以重写的方法: ```py class scrapy.pipelines.files.FilesPipeline ``` ```py get_media_requests(item, info) ``` 如工作流上所示,管道将从项目中获取要下载的图像的URL。为此,可以重写 [`get_media_requests()`](#scrapy.pipelines.files.FilesPipeline.get_media_requests "scrapy.pipelines.files.FilesPipeline.get_media_requests") 方法并返回每个文件的请求URL:: ```py def get_media_requests(self, item, info): for file_url in item['file_urls']: yield scrapy.Request(file_url) ``` 这些请求将由管道处理,下载完成后,结果将发送到 [`item_completed()`](#scrapy.pipelines.files.FilesPipeline.item_completed "scrapy.pipelines.files.FilesPipeline.item_completed") 方法,作为2元素元组的列表。每个元组将包含 `(success, file_info_or_error)` 在哪里? * `success` 是一个布尔值,它是 `True` 如果图像下载成功或 `False` 如果因为某种原因失败了 * `file_info_or_error` 是包含以下键的dict(如果成功是 `True` 或A [Twisted Failure](https://twistedmatrix.com/documents/current/api/twisted.python.failure.Failure.html) 如果有问题的话。 * `url` -从中下载文件的URL。这是从 [`get_media_requests()`](#scrapy.pipelines.files.FilesPipeline.get_media_requests "scrapy.pipelines.files.FilesPipeline.get_media_requests") 方法。 * `path` -路径(相对于 [`FILES_STORE`](#std:setting-FILES_STORE) )文件的存储位置 * `checksum` -A [MD5 hash](https://en.wikipedia.org/wiki/MD5) 图像内容的 接收的元组列表 [`item_completed()`](#scrapy.pipelines.files.FilesPipeline.item_completed "scrapy.pipelines.files.FilesPipeline.item_completed") 保证保留从 [`get_media_requests()`](#scrapy.pipelines.files.FilesPipeline.get_media_requests "scrapy.pipelines.files.FilesPipeline.get_media_requests") 方法。 以下是 `results` 论点: ```py [(True, {'checksum': '2b00042f7481c7b056c4b410d28f33cf', 'path': 'full/0a79c461a4062ac383dc4fade7bc09f1384a3910.jpg', 'url': 'http://www.example.com/files/product1.pdf'}), (False, Failure(...))] ``` 默认情况下 [`get_media_requests()`](#scrapy.pipelines.files.FilesPipeline.get_media_requests "scrapy.pipelines.files.FilesPipeline.get_media_requests") 方法返回 `None` 这意味着该项目没有可下载的文件。 ```py item_completed(results, item, info) ``` 这个 [`FilesPipeline.item_completed()`](#scrapy.pipelines.files.FilesPipeline.item_completed "scrapy.pipelines.files.FilesPipeline.item_completed") 当单个项的所有文件请求都已完成时调用的方法(要么已完成下载,要么由于某种原因失败)。 这个 [`item_completed()`](#scrapy.pipelines.files.FilesPipeline.item_completed "scrapy.pipelines.files.FilesPipeline.item_completed") 方法必须返回将发送到后续项管道阶段的输出,因此必须返回(或删除)该项,就像在任何管道中一样。 下面是一个 [`item_completed()`](#scrapy.pipelines.files.FilesPipeline.item_completed "scrapy.pipelines.files.FilesPipeline.item_completed") 方法,将下载的文件路径(传入结果)存储在 `file_paths` 项目字段,如果该项目不包含任何文件,则将其删除:: ```py 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()`](#scrapy.pipelines.files.FilesPipeline.item_completed "scrapy.pipelines.files.FilesPipeline.item_completed") 方法返回项。 请参见以下自定义图像管道中可以覆盖的方法: ```py class scrapy.pipelines.images.ImagesPipeline ``` > 这个 [`ImagesPipeline`](#scrapy.pipelines.images.ImagesPipeline "scrapy.pipelines.images.ImagesPipeline") 是 `FilesPipeline` ,自定义字段名并为图像添加自定义行为。 ```py get_media_requests(item, info) ``` 工作方式与 `FilesPipeline.get_media_requests()` 方法,但对图像URL使用不同的字段名。 必须返回每个图像URL的请求。 ```py item_completed(results, item, info) ``` 这个 [`ImagesPipeline.item_completed()`](#scrapy.pipelines.images.ImagesPipeline.item_completed "scrapy.pipelines.images.ImagesPipeline.item_completed") 当一个项目的所有图像请求都已完成时(要么已完成下载,要么由于某种原因失败),将调用方法。 工作方式与 `FilesPipeline.item_completed()` 方法,但使用不同的字段名存储图像下载结果。 默认情况下, [`item_completed()`](#scrapy.pipelines.images.ImagesPipeline.item_completed "scrapy.pipelines.images.ImagesPipeline.item_completed") 方法返回项。 ## 自定义图像管道示例 下面是一个完整的图像管道示例,其方法如上所示: ```py 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 ```