You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scrapy/Python:如何等待yield图片下载完成后再执行生成PDF代码

问题原因

Scrapy 的 Item Pipeline 是异步执行的,你在 parse_chapter 中 yield 包含图片链接的 item 之后,代码不会阻塞等待图片管道完成下载,会直接执行后续的 self.create_pdf(),所以会出现图片还未全部下载完成就开始生成 PDF 的问题。

推荐解决方案:在图片管道中监听下载完成事件

Scrapy 内置的 ImagesPipeline 提供了 item_completed 方法,会在当前 item 关联的所有图片下载完成后自动调用,你可以在这里触发 PDF 生成逻辑,是成本最低的实现方式。

步骤1:调整 parse_chapter 返回内容

为了区分不同章节的图片,你需要在返回的 item 中加入章节的唯一标识(比如章节URL、章节名、自定义章节ID),同时如果一个章节有多张图,要把提取方法从 get() 改为 getall():

def parse_chapter(self, response):
    logging.debug("parse_chapter")
    # 提取章节唯一标识,示例用URL后缀当ID,你可以替换为自己提取的章节名
    chapter_id = response.url.split("/")[-1]
    # 单张图保留get()也可,多张图必须用getall()
    image_urls = response.xpath('/html/body/div[1]/div[3]/div/div[2]/div[2]/a/img/@src').getall()

    yield {
        'image_urls' : image_urls,
        'chapter_id': chapter_id
    }

步骤2:重写图片管道的 item_completed 方法

在你已修改的 pipelines.py 中,调整自定义的图片管道代码:

from scrapy.pipelines.images import ImagesPipeline
from scrapy.exceptions import DropItem

class CustomImagePipeline(ImagesPipeline):
    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
        item['image_paths'] = image_paths
        
        # 调用爬虫中定义的create_pdf方法,传入章节标识和图片路径
        info.spider.create_pdf(item['chapter_id'], item['image_paths'])
        return item

步骤3:调整 create_pdf 方法适配新逻辑

def create_pdf(self, chapter_id, image_paths):
    # 此处image_paths就是当前章节所有已完成下载的图片路径,直接生成PDF即可
    # 生成PDF完成后再删除对应图片即可
    ...
其他可选方案

如果不想修改管道,也可以通过 scrapy.signals.item_completed 信号监听所有item的处理状态,统计对应章节的图片下载完成度,全部下载完成后再触发PDF生成,不过实现复杂度比修改管道高,更推荐上述方案。

内容的提问来源于stack exchange,提问作者Romain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 18:54:00