如何在Scrapy爬虫完成抓取时将结束时间写入JSON文件
Scrapy爬虫结束时间写入JSON实现方案
首先明确核心逻辑:爬虫结束时间是爬虫完全停止后才会生成的全局值,无法在单条数据采集的parse_items阶段直接获取,需要结合Spider的生命周期方法和Pipeline配合实现。
一、先修改CrawlSpider代码,解决startUrl、productUrl获取+结束时间生成的问题
from scrapy.http import Request from scrapy.spiders import CrawlSpider, Rule from scrapy.linkextractors import LinkExtractor from ebaycomp.items import EbayItem from datetime import datetime class EbaySpider(CrawlSpider): name = 'spider' allowed_domains = ['ebay.co.uk'] start_urls = [ 'https://www.ebay.co.uk/sch/49831/i.html?_from=R40&_nkw=chain+and+sprocket+kit&LH_ItemCondition=1000&rt=nc&LH_PrefLoc=1', 'https://www.ebay.co.uk/sch/177771/i.html?_from=R40&_nkw=motorcycle+air+filter&LH_ItemCondition=1000&rt=nc&LH_PrefLoc=1' ] rules = [ Rule( LinkExtractor( allow=('.*'), restrict_xpaths=[ '//a[@class="s-item__link"][1]', '//a[@class="s-item__link"][2]', '//a[@class="s-item__link"][3]' ] ), callback='parse_items', follow=True, # 传递父请求的meta到子请求,保留start_url标记 process_request=lambda request, response: request.replace(meta=response.meta) ) ] # 重写起始请求方法,给每个起始列表页带上start_url标记 def start_requests(self): for url in self.start_urls: yield Request(url, meta={"start_url": url}) def parse_items(self, response): scrapedItem = EbayItem() # 从meta中取当前商品对应的起始列表页URL scrapedItem['startUrl'] = response.meta.get("start_url") # 当前页面URL就是商品详情页URL scrapedItem['productUrl'] = response.url scrapedItem['productTitle'] = response.xpath('//h1/text()').get() scrapedItem['productPrice'] = response.xpath('//span[@itemprop="price"]/text()').get() # 此处无需赋值timeClosed,后续在Pipeline统一处理 return scrapedItem # 爬虫关闭时自动触发,生成结束时间存储到spider实例 def closed(self, reason): self.end_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") self.close_reason = reason
二、修改JsonWriterPipeline,按需求写入结束时间
场景1:所有商品条目都附带爬虫结束时间(适合小数据量采集)
需要先把所有采集到的item暂存在内存里,等爬虫结束后统一填充结束时间再写入文件:
import json from scrapy.item import ItemAdapter class JsonWriterPipeline: def open_spider(self, spider): self.item_buffer = [] self.file = open('ebay_out.jl', 'w', encoding='utf-8') def close_spider(self, spider): # 爬虫关闭后,给所有暂存的item填充结束时间再写入 end_time = spider.end_time for item in self.item_buffer: item['timeClosed'] = end_time line = json.dumps(ItemAdapter(item).asdict(), ensure_ascii=False) + "\n" self.file.write(line) self.file.close() def process_item(self, productItem, spider): # 先把item放到缓冲区暂存 self.item_buffer.append(productItem) return productItem
场景2:文件末尾追加独立的爬虫结束统计记录(适合大数据量采集,无需暂存)
不需要修改单条商品数据,只需要在所有商品写入完成后,追加一条统计记录即可:
import json from scrapy.item import ItemAdapter class JsonWriterPipeline: def open_spider(self, spider): self.file = open('ebay_out.jl', 'w', encoding='utf-8') self.item_count = 0 def close_spider(self, spider): # 追加结束统计记录 end_info = { "record_type": "spider_close_info", "end_time": spider.end_time, "close_reason": spider.close_reason, "total_collected_count": self.item_count } line = json.dumps(end_info, ensure_ascii=False) + "\n" self.file.write(line) self.file.close() def process_item(self, productItem, spider): line = json.dumps(ItemAdapter(productItem).asdict(), ensure_ascii=False) + "\n" self.file.write(line) self.item_count += 1 return productItem
三、最后配置生效
在settings.py中开启Pipeline即可:
ITEM_PIPELINES = { # 替换为你自己项目中Pipeline的实际路径 'ebaycomp.pipelines.JsonWriterPipeline': 300, }
内容的提问来源于stack exchange,提问作者George
相关产品推荐
相关产品推荐

