Scrapy爬取RacingPost历史赛马结果:循环生成链接还是预定义列表更优?
Scrapy实现1990年至今日期遍历的方法
在爬虫的start_requests方法中嵌入按天遍历的日期生成逻辑即可,仅靠Python标准库的日期处理能力就能满足需求,不需要依赖第三方组件或模拟JS交互,核心实现如下:
import scrapy from datetime import datetime, timedelta class RacingPostSpider(scrapy.Spider): name = "racing_history" BASE_RESULTS_URL = "https://www.racingpost.com/results/" def start_requests(self): # 定义爬取时间区间 crawl_start = datetime(1990, 1, 1) crawl_end = datetime.today() cur_date = crawl_start # 按天循环生成目标链接 while cur_date <= crawl_end: # 匹配站点要求的日期格式 date_segment = cur_date.strftime("%Y-%m-%d") full_url = f"{self.BASE_RESULTS_URL}{date_segment}" # 附带当前日期标记,减少后续解析的字段提取成本 yield scrapy.Request( url=full_url, meta={"crawl_date": date_segment}, callback=self.parse_page ) # 日期步进1天 cur_date += timedelta(days=1) def parse_page(self, response): # 后续页面解析逻辑从response.meta中直接读取爬取日期即可 current_crawl_date = response.meta["crawl_date"] # 提取赛事数据的业务逻辑... pass
这种实现完全适配站点的URL规则,不需要做额外的参数拼接或JS模拟。
两种实现方案的适配性对比
预定义全量链接列表方案
这种方案就是提前写个脚本,把从1990-01-01到当前日期的所有日期拼好成完整URL,直接赋值给爬虫的start_urls属性启动爬取。
- 优点:实现最简单,不需要额外写循环逻辑,照着Scrapy基础文档就能写出来
- 实际使用的问题:
- 内存占用高:按跨度34年算,全量大概1.2万+条链接,Scrapy启动时会把所有链接一次性加载到调度队列,低配置服务器很容易出现内存吃紧的问题
- 调整成本高:如果后续需要改爬取范围(比如不爬1990-2000年的早期数据、优先爬近年的赛事),必须重新生成全量链接列表,没法灵活调整
- 断点续爬麻烦:爬虫中途中断后,需要拿已爬的链接列表和全量预定义列表做差集,才能定位到上次爬的位置,效率很低
动态循环遍历方案
就是前面代码示例里写的,在start_requests里按日期步进生成链接的方式。
- 优势:
- 资源占用极低:每次循环只生成1个待爬链接,不会一次性把全量URL加载到内存,哪怕在1G内存的小服务器上也能平稳运行
- 断点续爬好做:只要把上次遍历到的日期存在本地文件里,下次启动时把循环的起始点设为这个日期就行,不需要做全量链接对比
- 调整灵活:可以在循环里随便加规则,比如跳过没有赛事的固定日期、把爬取顺序从远到近改成从近到远(优先拿高价值的近期数据)、按年度分段控制爬取速度
- 唯一的小缺点:比直接写
start_urls多了几行循环代码,没有预定义列表那么一目了然
最终适配结论:这个站点的URL是完全无参数的静态结构,用动态循环遍历的方案远优于预定义全量列表,后续维护和调整的成本低很多。
实操提醒
- 一定要在settings里配置合理的
DOWNLOAD_DELAY,别刚爬两天就被站点封IP- 对返回404的日期请求直接跳过就行,不用设置太高的重试次数,毕竟不是每天都有赛马赛事
- 长期跑的话建议把已经爬完的日期同步存在本地轻量存储里,避免爬虫意外重启后重复爬取已处理的历史数据
内容的提问来源于stack exchange,提问作者Phil
相关产品推荐
相关产品推荐

