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

Scrapy中parse函数的yield item处理机制及底层实现疑问

关于Scrapy中parse函数与yield生成器的疑问

我刚接触generator(生成器)和yield,若有表述不当之处还请见谅。

为说明问题,先举一个基础示例:在函数内的循环中使用yield时,该函数会成为生成器,只有将其作为可迭代对象遍历、用循环调用或多次调用next()函数,才能让内部循环完成所有yield操作。示例如下:

def parse():
    for i in range(10):
        yield i

若要输出0到9的所有数值,可通过以下方式实现:

x = parse()
list(x)

或者

for i in parse():
    print(i)

核心点是:必须完整迭代生成器,才能获取所有yield值,让函数内的循环完成全部迭代。

但Scrapy的处理方式让我困惑,以下是Scrapy示例代码:

class QuoteSpider(scrapy.Spider):
    name = 'quote-spdier'
    start_urls = ['https://quotes.toscrape.com']

    def parse(self, response):
        QUOTE_SELECTOR = '.quote'
        TEXT_SELECTOR = '.text::text'
        AUTHOR_SELECTOR = '.author::text'
        
        for quote in response.css(QUOTE_SELECTOR):
            yield {
                'text': quote.css(TEXT_SELECTOR).extract_first(),
                'author': quote.css(AUTHOR_SELECTOR).extract_first(),
            }

我理解每个start_url仅会调用一次parse函数并传入页面响应。假设单页面有多个产品,且只有一个start_url,parse函数仅被调用一次。此时循环遍历页面所有产品并逐个yield对象,但运行爬虫却能获取所有产品。我对此感到困惑:为何parse仅调用一次就能返回所有item?毕竟用next()调用生成器只能获取第一个yield值。

我想了解Scrapy的parse函数底层实现逻辑:是在内部循环调用parse?还是调用next(parse())?以此加深对yield和生成器的理解。


解答

你的核心困惑在于对Scrapy处理parse返回生成器的逻辑理解有误,直接拆解底层运行机制:

  1. parse仅被调用一次,返回生成器实例
    当Scrapy处理start_url的响应时,确实只会调用一次parse(response),但这个调用不会立即执行函数内部代码,而是直接返回一个生成器对象——和你写的基础生成器示例逻辑完全一致。

  2. Scrapy会完整迭代生成器,而非仅调用一次next()
    Scrapy拿到生成器后,不会只执行一次next(),而是像你用for循环遍历生成器、或用list()转换生成器那样,持续迭代直到生成器耗尽:

    • 每一次next()调用,都会让生成器执行到下一个yield语句,返回对应的item;
    • 直到生成器内部的for quote in response.css(QUOTE_SELECTOR)循环全部执行完毕,生成器抛出StopIteration异常,Scrapy才会停止迭代。
  3. Scrapy的核心处理逻辑等价于遍历生成器
    用伪代码简化表示Scrapy内部的处理流程:

# 获取parse返回的生成器
generator = spider.parse(response)
# 完整迭代生成器
for output in generator:
    if isinstance(output, dict):  # 处理yield的item
        process_and_save_item(output)
    elif isinstance(output, scrapy.Request):  # 处理yield的新请求
        schedule_new_request(output)

总结:不是Scrapy在循环调用parse函数,而是它拿到parse返回的生成器后,主动完成了整个迭代过程,从而获取到所有yield出来的item。这完全符合生成器的工作机制——只要完整迭代生成器,就能拿到所有yield的值。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 15:48:30