Scrapy 中 `file_path` 方法被多次调用的原因及排查方法

在使用 Scrapy 下载图片时,你可能会发现 file_path 方法被多次调用。这篇博客将解释为什么会发生这种情况,并提供一个排查方法,帮助你理解和解决这个问题。

问题描述

你在下载图片时,发现 file_path 方法被调用了三次。以下是简化后的代码示例:

import scrapy
from scrapy.pipelines.images import ImagesPipeline
import traceback

def sanitize_filename(filename):
    import re
    sanitized = re.sub(r'[<>:"/\\|?*]', '_', filename)
    return sanitized

class BiantuDownPicSavePipeline(ImagesPipeline):

    def get_media_requests(self, item, info):
        min_url = item['min_url']
        print('1. 发送请求去下载图片, min_url:', min_url)
        return scrapy.Request(url=min_url, meta={'item': item})

    def file_path(self, request, response=None, info=None, *, item=None):
        print('2. 图片的存储路径')
        item = request.meta['item']

        # 打印调用堆栈信息
        print("file_path called")
        traceback.print_stack()

        filename = item['title_min']
        filename = sanitize_filename(filename)
        return filename

    def item_completed(self, results, item, info):
        print(f'3. 对Item进行更新, result: {results}')

        if results:
            ok, res = results[0]
            if ok:
                item['min_path'] = res["path"]
        return item

排查方法

第一步:添加调试信息

file_path 方法中,我们添加了 traceback.print_stack() 来打印调用堆栈信息,以便我们能看到 file_path 方法每次被调用的具体位置。

第二步:运行代码并查看调试输出

当你运行这段代码时,你会看到类似以下的输出:

1. 发送请求去下载图片, min_url: https://pic.netbian.com/uploads/allimg/240509/010156-1715187716fada.jpg
2. 图片的存储路径
file_path called
  File "path/to/your_script.py", line XX, in <module>
    main()
  ...
3. 对Item进行更新, result: [(True, {'url': 'https://pic.netbian.com/uploads/allimg/240509/010156-1715187716fada.jpg', 'path': 'sanitized_filename.jpg', 'checksum': 'checksum_value', 'status': 'uptodate'})]

每次 file_path 被调用时,堆栈信息会显示其调用路径。

为什么 file_path 会被多次调用?

原因一:Scrapy 重试机制

Scrapy 有一个内置的重试机制,当第一次下载失败时,Scrapy 会自动重试几次(默认最多重试 2 次),总共尝试 3 次。如果图片下载在第一次或第二次失败,Scrapy 会再次调用 file_path 方法。

原因二:并发请求

如果在爬虫设置中启用了并发请求,并且对同一图片 URL 发送了多个并发请求,每个请求都会调用 file_path 方法来生成文件存储路径。

原因三:Scrapy 多次处理

Scrapy 在处理一个 item 时,可能会多次调用 file_path 方法来确认文件路径。特别是在处理管道(pipeline)和下载媒体(media)文件时。

解决方法

减少重试次数

你可以在 settings.py 中设置 RETRY_TIMES 为 0 或 1,以减少重试次数。

RETRY_TIMES = 1

增加下载延迟

如果是因为并发请求导致的,可以增加下载延迟或减少并发请求数。

DOWNLOAD_DELAY = 1
CONCURRENT_REQUESTS = 1

检查缓存机制

如果是因为 Scrapy 内部缓存机制导致的多次调用,可以检查 Scrapy 的缓存设置,确保没有不必要的缓存。

HTTPCACHE_ENABLED = False

总结

file_path 方法被多次调用的原因可能是 Scrapy 的重试机制、并发请求处理以及内部多次处理 item 的机制。通过添加详细的调试信息并分析调用堆栈,可以准确找出多次调用的具体原因,并采取相应的措施进行优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值