【爬虫入门第13讲】Scrapy 框架深度解析(四)核心配置与自定义扩展

Scrapy Settings 深度解析:核心配置与自定义扩展实战指南

引言

Scrapy 作为 Python 生态中最强大的爬虫框架之一,其灵活性与可扩展性很大程度上源于 settings.py 中的配置体系。无论是控制爬虫行为、优化性能,还是注入自定义逻辑,理解这些配置都是进阶的必经之路。本文将深入剖析六个核心配置项,并手把手教你编写自定义扩展(Extension),让你真正掌控 Scrapy 的运行机制。


第一部分:核心配置详解

1. 并发数量(CONCURRENT_REQUESTS)

作用:控制 Scrapy 同时发起的最大请求数。直接影响爬取速度与目标服务器压力。

python 复制代码
# settings.py
CONCURRENT_REQUESTS = 16  # 默认值 16

多角度解读

  • 性能调优:对于高带宽、低延迟的目标,可适当提高至 32~64;对于慢速或反爬严格的站点,建议降低至 4~8,避免被封 IP。
  • 资源限制:若爬虫运行在低配服务器或共享主机上,过高的并发会导致内存溢出(每个请求的 Response 对象会暂存于内存)。
  • 与 DOWNLOAD_DELAY 的协同:并发数高但延时低,可能瞬间打爆服务器;反之,低并发配合合理延时更稳健。

进阶技巧 :可通过 CONCURRENT_REQUESTS_PER_DOMAINCONCURRENT_REQUESTS_PER_IP 进一步细化控制,例如对同一域名限制并发为 8,对同一 IP 限制为 4。


2. 请求延时(DOWNLOAD_DELAY)

作用:设置两次连续请求之间的最小间隔(秒),用于降低爬取频率,模拟人类行为。

python 复制代码
DOWNLOAD_DELAY = 0.5  # 单位秒,默认 0

注意事项

  • 延时是随机化 的,实际间隔为 DOWNLOAD_DELAYDOWNLOAD_DELAY + RANDOMIZE_DOWNLOAD_DELAY(默认开启)之间的随机值,避免规律性被检测。
  • 若同时设置 CONCURRENT_REQUESTSDOWNLOAD_DELAY,Scrapy 会尽量保证总请求速率不超过 1 / DOWNLOAD_DELAY 个/秒(按域名或 IP 分组)。
  • 对于需要高吞吐的场景(如抓取自家 API),可设为 0 并配合高并发;但对外部站点,建议至少 1~3 秒。

实战建议 :结合 AUTOTHROTTLE_ENABLED = True 启用自动限速,Scrapy 会根据服务器响应时间动态调整延时,比固定值更智能。


3. 用户代理配置(USER_AGENT 与 DEFAULT_REQUEST_HEADERS)

作用:伪装请求头中的 User-Agent,避免被识别为爬虫。

python 复制代码
# 方式一:全局 UA
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'

# 方式二:自定义请求头(可覆盖 UA)
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'User-Agent': 'Mozilla/5.0 ...',  # 优先级高于 USER_AGENT
}

深度解析

  • 单一 UA 容易被反爬系统标记,建议使用 scrapy.downloadermiddlewares.useragent.UserAgentMiddleware 配合随机 UA 池(如 fake-useragent 库)。
  • 更高级的做法:在 settings.py 中禁用默认 UA 中间件,并编写自定义中间件从列表中随机选取 UA。
  • 注意:某些站点会校验 Sec-Ch-Ua 等新式头,需同步更新。

4. 日志等级(LOG_LEVEL)

作用:控制控制台输出的日志详细程度,便于调试与生产环境监控。

python 复制代码
LOG_LEVEL = 'INFO'  # 可选:DEBUG, INFO, WARNING, ERROR, CRITICAL

使用场景

  • 开发阶段 :设为 DEBUG,可看到每个请求的详细信息、中间件调用链、管道处理过程。
  • 生产环境 :设为 INFOWARNING,避免日志刷屏,同时保留关键错误信息。
  • 日志文件 :配合 LOG_FILE = 'scrapy.log' 将日志持久化,便于事后分析。

进阶 :可通过 LOG_FORMAT 自定义日志格式,例如添加时间戳、线程 ID 等;或使用 LOG_ENABLED = False 完全禁用日志(不推荐)。


5. 关闭 robots.txt 协议(ROBOTSTXT_OBEY)

作用 :是否遵守目标网站的 robots.txt 规则。默认 True,即 Scrapy 会先请求 robots.txt 并解析,禁止爬取被 Disallow 的路径。

python 复制代码
ROBOTSTXT_OBEY = False  # 生产环境通常设为 False

为什么关闭

  • 许多网站(尤其是中小站点)的 robots.txt 配置过于宽泛,会误伤合法爬取。
  • 爬取公开数据时,遵守 robots.txt 是道德要求,但法律上并非强制(视国家/地区而定)。建议在爬取前评估目标站点的条款。
  • 若必须遵守,可设置 ROBOTSTXT_USER_AGENT 指定用于解析 robots.txt 的 UA,避免与爬虫 UA 冲突。

注意 :关闭后仍需通过 DOWNLOAD_DELAYCONCURRENT_REQUESTS 控制礼貌性,否则可能被 IP 封禁。


6. 开启管道(ITEM_PIPELINES)

作用:注册并启用 Item Pipeline 组件,用于处理爬取到的数据(清洗、验证、存储等)。

python 复制代码
ITEM_PIPELINES = {
'myproject.pipelines.MyPipeline': 300,  # 数字越小优先级越高
'myproject.pipelines.DuplicatesPipeline': 200,
}

配置要点

  • 每个 Pipeline 类需实现 process_item(self, item, spider) 方法,返回 Item 或 DropItem 异常。
  • 优先级数字(0~1000)决定执行顺序:数字小的先执行。通常将数据清洗放在前面(如 100~300),存储放在后面(如 800~1000)。
  • 若需异步存储(如写入数据库),可继承 scrapy.pipelines.images.ImagesPipeline 等内置管道,或使用 Twisted 的 defer 机制。

常见管道示例

  • 去重管道:检查 Item 的某个字段是否已存在。
  • 数据清洗管道:去除空格、转换类型、填充默认值。
  • 存储管道:写入 CSV、JSON、MySQL、MongoDB 等。

第二部分:自写扩展(Extension)指南

扩展是什么?

Scrapy 扩展(Extension)是框架的"插件系统",允许你在爬虫生命周期的关键节点(如启动、关闭、收到响应、发生错误等)注入自定义逻辑。与中间件不同,扩展不直接处理请求/响应,而是用于监控、统计、资源管理等全局性任务。

扩展的工作原理

Scrapy 使用 signals(信号)机制触发事件。扩展类需继承 object,并在 from_crawler 类方法中连接信号。常用信号包括:

信号 触发时机 常用场景
engine_started 引擎启动时 初始化资源、打印启动信息
spider_opened 爬虫打开时 读取配置、建立数据库连接
spider_closed 爬虫关闭时 清理资源、生成统计报告
item_scraped 每个 Item 被爬取后 实时计数、写入缓存
request_scheduled 请求被调度时 监控请求队列长度
response_received 收到响应时 记录响应状态码分布

实战:编写一个爬虫运行统计扩展

假设我们需要统计爬虫运行期间的总请求数、成功数、失败数、平均响应时间,并在爬虫关闭时输出报告。

步骤 1:创建扩展类

myproject/extensions.py 中编写:

python 复制代码
from scrapy import signals
from scrapy.exceptions import NotConfigured

class StatsExtension:
    """统计爬虫运行指标"""
    
    def __init__(self, stats_enabled=True):
        self.stats_enabled = stats_enabled
        self.total_requests = 0
        self.success_count = 0
        self.failure_count = 0
        self.total_response_time = 0.0
        self.response_count = 0

    @classmethod
    def from_crawler(cls, crawler):
        # 从 settings 中读取配置,若未启用则跳过
        if not crawler.settings.getbool('STATS_EXTENSION_ENABLED', True):
            raise NotConfigured
        
        ext = cls()
        # 连接信号
        crawler.signals.connect(ext.request_scheduled, signal=signals.request_scheduled)
        crawler.signals.connect(ext.response_received, signal=signals.response_received)
        crawler.signals.connect(ext.spider_closed, signal=signals.spider_closed)
        return ext

    def request_scheduled(self, request, spider):
        self.total_requests += 1

    def response_received(self, response, request, spider):
        self.response_count += 1
        # 假设 response 对象有 meta 中记录了开始时间
        start_time = request.meta.get('start_time')
        if start_time:
            elapsed = response.meta.get('download_latency', 0)  # 或自行计算
            self.total_response_time += elapsed
        if 200 <= response.status < 300:
            self.success_count += 1
        else:
            self.failure_count += 1

    def spider_closed(self, spider, reason):
        avg_time = self.total_response_time / self.response_count if self.response_count else 0
        print(f"\n===== 爬虫统计报告 =====")
        print(f"总请求数: {self.total_requests}")
        print(f"成功响应: {self.success_count}")
        print(f"失败响应: {self.failure_count}")
        print(f"平均响应时间: {avg_time:.3f} 秒")
        print(f"爬虫关闭原因: {reason}")
        print("========================\n")
步骤 2:在 settings.py 中启用扩展
python 复制代码
# 启用扩展
EXTENSIONS = {
'myproject.extensions.StatsExtension': 500,  # 优先级数字
}

# 自定义配置(可选)
STATS_EXTENSION_ENABLED = True
步骤 3:在 Spider 中记录请求开始时间(可选)

为了精确计算响应时间,可以在 Spider 的 start_requestsparse 方法中给 Request 添加 start_time

python 复制代码
import time

def start_requests(self):
	for url in self.start_urls:
		yield scrapy.Request(url, meta={'start_time': time.time()})

然后在扩展的 response_received 中通过 request.meta['start_time'] 计算耗时。

扩展的高级用法

  1. 动态配置 :通过 crawler.settings 读取自定义配置项,实现开关、阈值等。
  2. 与 Pipeline 交互 :扩展可以访问 crawler.stats 对象(Scrapy 内置统计),或通过 crawler.engine 获取调度器状态。
  3. 异步操作 :若需在扩展中执行异步任务(如发送 HTTP 请求),可使用 deferToThreadreactor.callLater
  4. 错误处理:在信号处理函数中捕获异常,避免影响爬虫主流程。

常见扩展场景

  • 自动暂停/恢复 :监听 spider_idle 信号,当无待处理请求时自动暂停爬虫。
  • 代理轮换 :在 request_scheduled 中动态修改 Request 的代理。
  • 数据备份 :在 spider_closed 中将内存中的缓存数据写入磁盘。
  • 邮件通知:爬虫异常时发送报警邮件。

总结

Scrapy 的配置体系是爬虫稳定运行的基石。通过合理调整并发、延时、UA、日志等核心参数,你可以在效率与礼貌之间找到平衡;而自定义扩展则赋予你无限可能------从简单的统计到复杂的自动化运维,都能通过几十行代码优雅实现。

记住:配置是骨架,扩展是血肉。掌握这两者,你就能从"会用 Scrapy"进阶到"驾驭 Scrapy"。

相关推荐
夜雪一千2 小时前
TCP数据包长什么样?拆解TCP报文头部结构
网络·网络协议·tcp/ip
德迅云安全杨德俊3 小时前
应用加速:一站式解决企业跨域网络加速与安全双重难题
网络·安全·ddos
瓦学妹3 小时前
什么是网络索引?它是如何工作的?
大数据·网络·python·网络爬虫
for_ever_love__5 小时前
iOS:网络请求再学习
网络·学习·ios·objective-c
一名普通的电源工程师6 小时前
E0512XT-1WR3 适配优选 钡特电源 DF1-05D12XT|1W 隔离5V转±12V模块电源选型参数技术解析
大数据·网络·人工智能
2301_780789666 小时前
零信任时代:WAF 从边界防护到微隔离的架构跃迁
网络·安全·web安全·kubernetes·ddos
regret~7 小时前
【记录】网络路由、转发与网卡隔离
linux·服务器·网络
牛马工作号7 小时前
蓝牙技术全景指南:从无线链路、协议栈到产品量产
网络
中电华星8 小时前
专业的工业电源公司
网络·python