Scrapy增量爬取问题:仅提取NDTV网站更新的第一条头条
解决Scrapy爬取NDTV头条仅更新新内容的问题
看起来你遇到的核心问题是DeltaFetch默认的去重逻辑不匹配你的需求——它是基于请求的整体指纹(比如URL、请求头、参数等)来判断是否爬过,但NDTV的top-stories页面每次加载可能带有动态元素(比如实时时间戳、广告组件),导致每次请求的指纹都不一样,所以DeltaFetch每次都会认为是新请求,进而更新.db文件和输出的json。
下面给你几个更精准的实现方案,按推荐程度排序:
方案一:自定义本地标识去重(最简单高效)
直接放弃DeltaFetch,自己实现基于第一条头条唯一标识的去重逻辑,比如用新闻的URL作为唯一判断依据(因为每条新闻的URL是唯一且不变的)。
具体步骤:
- 在爬虫代码里,先提取页面第一条头条的URL;
- 读取本地存储的“上次爬取的第一条头条URL”;
- 对比两者:如果不同,就提取这条新闻的内容并保存,同时更新本地存储;如果相同,直接终止爬取。
代码示例:
import scrapy class NDTVTopStoriesSpider(scrapy.Spider): name = 'test' start_urls = ['https://www.ndtv.com/top-stories'] def parse(self, response): # 提取第一条头条的核心信息 first_headline = response.css('.new_story h2 a') if not first_headline: self.logger.warning('No headline found on the page') return current_url = first_headline.attrib['href'] current_title = first_headline.css('::text').get().strip() current_time = response.css('.new_story .dateline::text').get().strip() # 读取本地记录的上次头条URL saved_url = '' try: with open('last_ndtv_headline.txt', 'r') as f: saved_url = f.read().strip() except FileNotFoundError: # 第一次运行,文件不存在,直接处理 pass if current_url != saved_url: # 生成Item yield { 'url': current_url, 'title': current_title, 'publish_time': current_time } # 更新本地记录 with open('last_ndtv_headline.txt', 'w') as f: f.write(current_url) self.logger.info('New headline found and saved!') else: self.logger.info('No update in top headline, stopping crawl.') return
配套设置:
- 在
settings.py里关闭DeltaFetch中间件,避免干扰:DOWNLOADER_MIDDLEWARES = { # 注释掉DeltaFetch相关的配置 # 'scrapy_deltafetch.DeltaFetch': 100, } - 运行爬虫时,如果想每次只保留最新的头条,可以用覆盖模式输出:
scrapy crawl test -o test.json --overwrite
方案二:修改DeltaFetch的指纹生成逻辑
如果你坚持要用DeltaFetch,可以自定义它的指纹生成规则,让指纹基于第一条头条的URL,而不是整个请求的指纹。
具体步骤:
- 在项目里新建一个
utils.py文件,定义自定义指纹函数:def headline_based_fingerprint(request, spider): # 核心思路:用第一条头条的URL作为去重标识 # 需要在爬虫请求的meta中传递已解析的头条URL if 'headline_url' in request.meta: return request.meta['headline_url'] # fallback到默认指纹 from scrapy.utils.request import request_fingerprint return request_fingerprint(request) - 在
settings.py里配置DeltaFetch使用这个自定义函数:DELTAFETCH_FINGERPRINT_FUNC = 'your_project.utils.headline_based_fingerprint' DELTAFETCH_ENABLED = True - 在爬虫的
parse方法里,把第一条头条的URL放到请求的meta中(需要调整爬虫逻辑,确保请求发送前已获取到头条URL)。
这个方法相对复杂,因为DeltaFetch的设计是针对请求级别的去重,而你的需求是内容级别的,所以方案一更适配。
方案三:使用Scrapy的dupefilter自定义去重
Scrapy自带的dupefilter也可以自定义去重规则,核心思路和方案一类似,但更贴合Scrapy的架构:
- 自定义一个去重过滤器,基于头条URL去重;
- 在
settings.py里配置使用这个过滤器。
不过这个实现成本比方案一高,对于你的简单需求来说,方案一已经足够。
内容的提问来源于stack exchange,提问作者user9208975
相关产品推荐
相关产品推荐

