如何用Python3/Scrapy批量下载指定时段Gaceta报纸PDF并加速脚本
嘿,我来帮你搞定这两个Scrapy爬取尼加拉瓜Gaceta报纸的问题!咱们一个一个来解决:
1. 给脚本加上时间范围过滤功能
核心思路是从页面提取报纸的日期,转换成可比较的日期对象,再和你设定的目标范围对比,只下载符合条件的PDF。
假设你现在的爬虫已经能提取到报纸的日期字符串,你可以这么修改:
步骤1:导入datetime模块,灵活定义时间范围
在爬虫文件里引入datetime,并通过初始化方法支持硬编码或命令行参数传入时间范围,方便后续拆分任务:
步骤2:解析日期并过滤
在parse方法里,把提取到的日期字符串转成datetime对象,判断是否在目标范围内,只有符合条件的才发起PDF下载请求。
给你个代码示例:
from datetime import datetime import scrapy class GacetaSpider(scrapy.Spider): name = 'gaceta' allowed_domains = ['asamblea.gob.ni'] start_urls = ['你的起始URL'] def __init__(self, start_date="1844-01-01", end_date="1900-01-01", *args, **kwargs): super().__init__(*args, **kwargs) # 把字符串转成datetime对象,格式要和页面提取的日期匹配 self.start_dt = datetime.strptime(start_date, "%Y-%m-%d") self.end_dt = datetime.strptime(end_date, "%Y-%m-%d") def parse(self, response): # 从页面提取日期字符串,CSS选择器需根据实际页面结构调整 date_text = response.css(".news-date::text").get().strip() # 注意:格式符要和页面日期格式一致,比如"01/01/1844"对应"%d/%m/%Y" try: article_dt = datetime.strptime(date_text, "%d/%m/%Y") except ValueError: self.logger.warning(f"无法解析日期:{date_text},跳过该条目") return # 判断是否在目标时间范围内 if self.start_dt <= article_dt <= self.end_dt: # 提取PDF链接,选择器需根据实际页面调整 pdf_link = response.css(".pdf-download::attr(href)").get() if pdf_link: # 拼接完整URL,发起下载请求 yield scrapy.Request( url=response.urljoin(pdf_link), callback=self.save_pdf ) else: self.logger.info(f"日期 {date_text} 不在目标范围内,跳过") def save_pdf(self, response): # 自定义保存逻辑,用URL末尾的文件名避免重复 pdf_filename = f"gaceta_{response.url.split('/')[-1]}" with open(pdf_filename, "wb") as f: f.write(response.body) self.logger.info(f"已保存:{pdf_filename}")
如果要通过命令行传范围,运行时可以这么写:
scrapy crawl gaceta -a start_date="1844-01-01" -a end_date="1900-01-01"
2. 用xargs或Scrapy内置设置加速下载
方式一:优化Scrapy内置并发参数
先试试调整settings.py,这是最简单的加速方式:
# 增加并发请求数(根据机器性能和网站承受能力调整,别太激进) CONCURRENT_REQUESTS = 32 # 每个域名的并发请求数 CONCURRENT_REQUESTS_PER_DOMAIN = 16 # 减少下载延迟(网站反爬不严格时可用) DOWNLOAD_DELAY = 0.25 # 禁用Cookie(无需登录或会话时开启) COOKIES_ENABLED = False # 启用自动限速,避免触发反爬 AUTOTHROTTLE_ENABLED = True AUTOTHROTTLE_START_DELAY = 0.25 AUTOTHROTTLE_MAX_DELAY = 1.0
方式二:用xargs拆分任务并行运行
如果单进程Scrapy还是不够快,可以把时间范围拆成小块(比如按年份),用xargs同时运行多个Scrapy实例。
步骤1:修改爬虫支持年份参数
把爬虫改成接受year参数,让每个实例只处理某一年的报纸:
def __init__(self, year=None, *args, **kwargs): super().__init__(*args, **kwargs) if year: self.start_dt = datetime(int(year), 1, 1) self.end_dt = datetime(int(year), 12, 31) else: # 默认时间范围 self.start_dt = datetime(1844, 1, 1) self.end_dt = datetime(1900, 1, 1)
步骤2:写bash脚本用xargs并行执行
创建run_parallel.sh:
#!/bin/bash # 生成1844到1900的年份列表 years=$(seq 1844 1900) # -P后面的数字是同时运行的进程数(根据CPU核心数调整,比如4或8) echo "$years" | xargs -n 1 -P 8 bash -c ' target_year=$1 echo "开始处理年份:$target_year" scrapy crawl gaceta -a year=$target_year ' _
给脚本加执行权限:
chmod +x run_parallel.sh
运行脚本即可同时处理多个年份的任务:
./run_parallel.sh
注意事项
- 并发数别设太高,容易被网站封IP,建议先从
-P 4测试 - 如果网站有反爬,可搭配代理池或适当调高
DOWNLOAD_DELAY - 保存PDF时尽量用唯一文件名,避免覆盖
内容的提问来源于stack exchange,提问作者Til Hund
相关产品推荐
相关产品推荐

