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

Scrapy爬需跳转两次URL,导出CSV数据乱序重复问题求助

Scrapy多级爬取数据乱序、重复问题解决方案

问题描述

我尝试从一个需要先访问2个URL才能爬取数据的网站获取数据,目标是得到指定格式的导出文件。我的代码如下:

import scrapy
from scrapy.item import Item, Field
from scrapy import Request

class myItems(Item):
    info1 = Field()
    info2 = Field()
    info3 = Field()
    info4 = Field()

class mySpider(scrapy.Spider):
    name = 'techbot'
    start_urls = ['']
    def parse(self, response):
        #Extracts first link
        items = []
        list1 = response.css("").extract() #extract all info from here
        for i in list1:
            link1 = 'https:...' + str(i)
            request = Request(link1, self.parseInfo1, dont_filter =True)
            request.meta['item'] = items
            yield request
        yield items

    def parseInfo1(self, response):
        #Extracts second link
        item = myItems()
        items = response.meta['item']
        list1 = response.css("").extract()
        for i in list1:
            link1 = '' + str(i)
            request = Request(link1, self.parseInfo2, dont_filter =True)
            request.meta['item'] = items
            items.append(item)
        return request

    def parseInfo2(self, response):
        #Extracts all data
        item = myItems()
        items = response.meta['item']
        item['info1'] = response.css("").extract()
        item['info2'] = response.css("").extract()
        item['info3'] = response.css("").extract()
        item['info4'] = response.css("").extract()
        items.append(item)
        return items

我在终端执行命令scrapy crawl techbot运行爬虫后,得到的数据出现乱序和重复问题,例如第一组数据被多次爬取,其余数据顺序混乱。恳请各位指点如何获取符合初始要求的规整格式数据,谢谢。


问题根源分析

我看了你的代码,核心问题出在Item的传递和数据收集逻辑混乱上:

  • 你在parse里创建了一个全局的items列表,所有请求都共享这个列表,导致多个请求同时往里面加数据,自然会出现重复和乱序。
  • parseInfo1和parseInfo2里重复创建myItems()实例,还错误地把整个列表绑定到request的meta中,而不是单个Item,最终导致数据被多次添加。
  • parse方法最后直接yield items,但此时异步请求还没完成,会提前输出空列表,后续parseInfo2又往同一个列表里塞数据,进一步加剧混乱。

修正后的代码

下面是调整后的代码,解决了上述问题,保证数据规整:

import scrapy
from scrapy.item import Item, Field
from scrapy import Request

class myItems(Item):
    info1 = Field()
    info2 = Field()
    info3 = Field()
    info4 = Field()

class mySpider(scrapy.Spider):
    name = 'techbot'
    # 替换成你的实际起始URL
    start_urls = ['https://your-start-url.com']

    def parse(self, response):
        # 提取第一级链接,替换成你的实际CSS选择器
        first_level_links = response.css("your-first-link-selector::attr(href)").extract()
        for link_suffix in first_level_links:
            full_link = 'https://your-base-domain.com' + link_suffix
            # 调度第一级页面请求,不需要提前创建Item
            yield Request(full_link, callback=self.parseInfo1, dont_filter=True)

    def parseInfo1(self, response):
        # 提取第二级链接,替换成你的实际CSS选择器
        second_level_links = response.css("your-second-link-selector::attr(href)").extract()
        for link_suffix in second_level_links:
            full_link = 'https://your-base-domain.com' + link_suffix
            # 为每个第二级请求创建独立的Item,绑定到meta中
            item = myItems()
            # 如果第一级页面有需要保存的字段,在这里赋值
            # item['some_field_from_level1'] = response.css(...)
            yield Request(full_link, callback=self.parseInfo2, meta={'item': item}, dont_filter=True)

    def parseInfo2(self, response):
        # 获取当前请求绑定的独立Item
        item = response.meta['item']
        # 提取目标数据,用extract_first()获取单个值,strip()清理格式
        item['info1'] = response.css("info1-selector::text").extract_first(default='').strip()
        item['info2'] = response.css("info2-selector::text").extract_first(default='').strip()
        item['info3'] = response.css("info3-selector::text").extract_first(default='').strip()
        item['info4'] = response.css("info4-selector::text").extract_first(default='').strip()
        # 直接输出单个Item,Scrapy会自动处理数据收集和导出
        yield item

关键修正说明

  1. 独立Item绑定:每个第二级请求都对应一个独立的myItems实例,避免多个请求共享同一个Item导致数据覆盖或重复。
  2. 异步请求正确调度:所有请求都通过yield交给Scrapy调度,框架会按请求顺序处理,保证数据的顺序性(只要网站结构允许)。
  3. 移除全局列表:不再用全局列表收集数据,而是在最终解析方法里直接yield单个Item,让Scrapy自动处理数据的存储和导出,避免异步请求未完成就提前输出。
  4. 优化数据提取:用extract_first()替代extract()获取单个字段值,加上default=''避免空值报错,strip()清理多余的空格和换行,让数据更规整。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:49:02