Scrapy多URL爬取时JSON数据顺序混乱问题求助
解决Scrapy多URL爬取时JSON数据顺序混乱的问题
问题说明
单URL爬取时脚本运行正常,JSON结构符合预期;但爬取同站点多个URL时,少量URL结果顺序正常,URL数量增多后,JSON数据顺序偶发混乱(比如第三个URL的title提前出现在第二个URL的相关数据前)。
原因分析
Scrapy是异步并发框架,多个请求会同时处理,不同URL的响应返回时间不确定,导致yield输出的item顺序和start_urls中的顺序不一致。
解决方案
方案一:强制顺序爬取(适合小量URL)
修改Scrapy的settings.py文件,限制并发请求数为1,让爬虫逐个处理URL,保证item顺序和start_urls一致:
# settings.py CONCURRENT_REQUESTS = 1 DOWNLOAD_DELAY = 0.5 # 可选,添加延迟避免触发站点反爬
优点:实现简单,不需要修改爬虫代码;缺点:牺牲并发效率,URL数量多时爬取速度变慢。
方案二:给Item添加URL标识,后续整理顺序(适合大量URL)
在每个输出的item中添加当前请求的URL字段,导出JSON后再按URL分组、按start_urls顺序重新整理数据,既保留并发效率,又能得到有序结果。
修改后的爬虫代码:
import scrapy class QuotesSpider(scrapy.Spider): name = "attributes" start_urls = [ "https://product.sanyglobal.com/concrete_machinery/truck_mixer/119/161/", "https://product.sanyglobal.com/concrete_machinery/truck_mixer/119/162/" ] def parse(self, response): current_url = response.url # 输出标题等基础信息 yield { "url": current_url, "title": response.css("div.sku-top-title::text").get(), "desc": response.css("div.sku-top-desc::text").get(), "brochure": 'brochure' } # 输出折叠面板内容 for post in response.css(".el-collapse"): headers = post.css(".el-collapse-item__header::text") desc_list = post.css(".value-el-desc") for i in range(len(headers)): res = "" x = desc_list[i].css(".value-el-desc p::text").extract() for y in x: res += y.strip() + "&&" try: yield { "url": current_url, "descTitle": headers[i].get().strip(), "desc": res } except: continue # 输出参数内容 for post in response.css(".lie-one-canshu"): try: yield { "url": current_url, "attribute": post.css('.lie-one-canshu::text')[0].get().strip() } except: continue
后续整理顺序的脚本:
导出JSON文件后,用以下脚本按start_urls顺序重新排列数据:
import json # 读取原始JSON数据 with open('attributes.json', 'r', encoding='utf-8') as f: raw_items = json.load(f) # 按URL分组存储item url_item_map = {} for item in raw_items: url = item["url"] if url not in url_item_map: url_item_map[url] = [] url_item_map[url].append(item) # 按照start_urls的顺序生成有序结果 target_order = [ "https://product.sanyglobal.com/concrete_machinery/truck_mixer/119/161/", "https://product.sanyglobal.com/concrete_machinery/truck_mixer/119/162/" ] sorted_items = [] for url in target_order: if url in url_item_map: sorted_items.extend(url_item_map[url]) # 保存整理后的JSON with open('sorted_attributes.json', 'w', encoding='utf-8') as f: json.dump(sorted_items, f, ensure_ascii=False, indent=2)
方案三:自定义Item Pipeline维护顺序(复杂场景)
如果需要在爬虫内部直接保证输出顺序,可以自定义Pipeline。核心思路是维护一个队列,按照start_urls的顺序缓存每个URL的item,所有请求完成后再按顺序输出。这种方式实现相对复杂,适合对实时输出顺序有严格要求的场景。
内容的提问来源于stack exchange,提问作者Aghilesdza
相关产品推荐
相关产品推荐

