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

Scrapy异步改造报错:'async_generator' object is not iterable

解决Scrapy异步改造后出现的TypeError: 'async_generator' object is not iterable问题

问题根源

Scrapy的start_requests方法要求返回可迭代对象(如生成器、列表),但你用async def结合yield将其定义成了异步生成器,Scrapy框架无法直接迭代异步生成器,因此抛出TypeError。同时parse方法直接使用await异步调用也不符合Scrapy的回调机制要求。

解决方案

  1. 用Twisted的inlineCallbacks和ensureDeferred工具,将异步逻辑包装成Scrapy可识别的Deferred对象,避免使用异步生成器
  2. 改造start_requests为普通方法,通过异步工具获取URL后生成请求
  3. 改造parse方法,将异步存储操作包装成Deferred,适配Scrapy的回调流程

修改后的完整代码

from scrapy import Spider, Request
from scrapy.linkextractors import LinkExtractor
from twisted.internet.defer import inlineCallbacks, ensureDeferred
import settings
from your_module import AsyncMySQLConnection, URLManager  # 替换为你的实际模块路径

class WebSpider(Spider):
    name = 'webspider'
    allowed_domains = allowed_domains

    custom_settings = {
        'RETRY_TIMES': 8,
        'RETRY_DELAY': 5,
        'RETRY_HTTP_CODES': [500, 502, 503, 504, 400, 403, 404, 408],
    }

    @staticmethod
    async def get_start_urls():
        async with AsyncMySQLConnection() as mysql_connection:
            urls = await mysql_connection.select_urls(settings.DATABASE_NAME, settings.TABLE_NAME)
        return urls

    @inlineCallbacks
    def start_requests(self):
        # 将异步获取URL的任务包装成Deferred,等待结果返回
        urls = yield ensureDeferred(self.get_start_urls())
        # 生成请求,返回可迭代的Request对象
        for url in urls:
            yield Request(url=url, callback=self.parse)

    @inlineCallbacks
    def parse(self, response):
        links = LinkExtractor(allowed_domains).extract_links(response)
        all_urls = [link.url for link in links]
        # 将异步存储操作包装成Deferred,交给Twisted事件循环处理
        yield ensureDeferred(URLManager().save_new_url_in_redis(all_urls))
        print(all_urls)

if __name__ == '__main__':
    from scrapy import cmdline
    cmdline.execute("scrapy crawl webspider".split())

关键修改点说明

  • 移除start_requests和parse的async修饰符,改用@inlineCallbacks装饰器,让Twisted处理异步逻辑
  • 用ensureDeferred包装异步函数(get_start_urls、save_new_url_in_redis),将其转换为Twisted的Deferred对象,通过yield等待异步任务完成
  • start_requests最终返回的是由Twisted管理的Deferred,其结果是可迭代的Request列表,符合Scrapy的要求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 17:16:20