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

如何将多页面抓取的响应写入单个文件/DataFrame?Scrapy扩展问题解析

解决Scrapy多页面抓取结果存入单个文件/ DataFrame的方案

我来帮你搞定这个问题!在Scrapy里把多页面爬取到的地理位置数据汇总到单个文件或者DataFrame里,有几种实用的方案,我给你一步步讲清楚:

方法1:用Scrapy自带的Feed Exports(最简单省心)

这是最不需要额外代码的方式,Scrapy内置了Feed导出功能,能自动把所有yield出来的Item收集起来,写入单个文件(支持JSON、CSV、XML等格式)。

使用方式:

  • 命令行直接指定:运行爬虫时加上-o参数,比如:
    scrapy crawl your_spider_name -o addresses.json
    
    或者导出为CSV(适合后续用Excel/ pandas处理):
    scrapy crawl your_spider_name -o addresses.csv
    
  • 在settings.py配置(永久生效):
    FEEDS = {
        'addresses.json': {
            'format': 'json',
            'encoding': 'utf-8',
            'overwrite': True,
        },
    }
    

优点:

  • 零额外代码,Scrapy自动处理Item的收集和存储
  • 支持多种格式,满足不同需求

方法2:自定义Item Pipeline存入DataFrame(灵活可控)

如果你需要后续用pandas做数据分析,自定义Pipeline是更专业的做法——在Pipeline里收集所有Item,爬虫结束时统一转成DataFrame并保存。

步骤1:编写Pipeline类(在pipelines.py里)

import pandas as pd

class DataFrameAddressPipeline:
    def open_spider(self, spider):
        # 初始化一个空列表,用来存所有爬取到的Item
        self.address_items = []

    def process_item(self, item, spider):
        # 把每个Item转成字典,加入列表
        self.address_items.append(dict(item))
        return item  # 必须返回Item,否则后续Pipeline无法处理

    def close_spider(self, spider):
        # 爬虫结束时,把列表转成DataFrame并保存
        df = pd.DataFrame(self.address_items)
        # 保存为CSV
        df.to_csv('addresses_data.csv', index=False, encoding='utf-8')
        # 也可以保存为JSON
        # df.to_json('addresses_data.json', orient='records', force_ascii=False)

步骤2:启用Pipeline(在settings.py里)

找到ITEM_PIPELINES配置,添加你的Pipeline:

ITEM_PIPELINES = {
    # 优先级数字越小,执行越早,300是合理的中间值
    'your_project_name.pipelines.DataFrameAddressPipeline': 300,
}

方法3:爬虫内部直接收集数据(适合小批量爬取)

如果你的爬取规模不大(比如几十上百个URL),可以在爬虫类里直接维护一个列表,收集所有结果,爬虫结束时统一处理。

修改后的爬虫代码:

import scrapy
from scrapy import Request
from your_project.items import MyItem
import pandas as pd
import json

class AddressSpider(scrapy.Spider):
    name = 'address_spider'
    start_urls = ['your_initial_start_url']  # 你的起始URL

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.all_addresses = []  # 用来存所有地址数据的列表

    def parse(self, response):
        # 假设这里是你生成URL列表的逻辑
        urls = [...]  # 替换成你的URL生成代码
        for url in urls:
            yield Request(url, callback=self.custom_parse)

        # 注意:你原来的time.sleep(3)在这里无效!Scrapy是异步框架,要控制请求间隔请用下面的方式
        # 在settings.py里配置 DOWNLOAD_DELAY = 3 即可实现每个请求间隔3秒

    def custom_parse(self, response):
        items = MyItem()
        tree = scrapy.Selector(response)
        # 这里建议优化XPath,避免用固定索引[3]——页面结构变化会导致抓取失败
        # 比如用包含关键词的XPath://script[contains(text(), 'addressInfo')]/text()
        script = tree.xpath('//script/text()').extract()[3]
        info = json.loads(script)
        items['address'] = info
        
        self.all_addresses.append(dict(items))  # 把当前Item加入列表
        yield items  # 依然要yield,确保Feed/Pipeline能正常工作

    def closed(self, reason):
        # 爬虫关闭时统一保存数据
        # 保存为DataFrame
        df = pd.DataFrame(self.all_addresses)
        df.to_csv('all_addresses.csv', index=False, encoding='utf-8')
        
        # 或者保存为JSON文件
        with open('all_addresses.json', 'w', encoding='utf-8') as f:
            json.dump(self.all_addresses, f, ensure_ascii=False, indent=2)

几个重要提醒:

  • 关于time.sleep(3):你原来在parse里加的time.sleep(3)是无效的!Scrapy是异步框架,parse方法里的sleep不会延迟Request的发送。要控制请求频率,请在settings.py里配置DOWNLOAD_DELAY = 3,或者开启自动节流AUTOTHROTTLE_ENABLED = True。
  • 优化XPath:避免用固定索引[3]定位script标签,页面结构变化会直接导致抓取失败。建议用包含内容关键词的XPath,比如//script[contains(text(), 'address')]/text(),精准定位目标script。
  • Item序列化:确保你的MyItem字段能正常转成字典,如果有复杂类型,需要在Item里定义序列化方法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:32:31