如何将多页面抓取的响应写入单个文件/DataFrame?Scrapy扩展问题解析
解决Scrapy多页面抓取结果存入单个文件/ DataFrame的方案
我来帮你搞定这个问题!在Scrapy里把多页面爬取到的地理位置数据汇总到单个文件或者DataFrame里,有几种实用的方案,我给你一步步讲清楚:
方法1:用Scrapy自带的Feed Exports(最简单省心)
这是最不需要额外代码的方式,Scrapy内置了Feed导出功能,能自动把所有yield出来的Item收集起来,写入单个文件(支持JSON、CSV、XML等格式)。
使用方式:
- 命令行直接指定:运行爬虫时加上
-o参数,比如:
或者导出为CSV(适合后续用Excel/ pandas处理):scrapy crawl your_spider_name -o addresses.jsonscrapy 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
相关产品推荐
相关产品推荐

