You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 09:31:49