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_DOMAIN 和 CONCURRENT_REQUESTS_PER_IP 进一步细化控制,例如对同一域名限制并发为 8,对同一 IP 限制为 4。
2. 请求延时(DOWNLOAD_DELAY)
作用:设置两次连续请求之间的最小间隔(秒),用于降低爬取频率,模拟人类行为。
python
DOWNLOAD_DELAY = 0.5 # 单位秒,默认 0
注意事项:
- 延时是随机化 的,实际间隔为
DOWNLOAD_DELAY到DOWNLOAD_DELAY + RANDOMIZE_DOWNLOAD_DELAY(默认开启)之间的随机值,避免规律性被检测。 - 若同时设置
CONCURRENT_REQUESTS和DOWNLOAD_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,可看到每个请求的详细信息、中间件调用链、管道处理过程。 - 生产环境 :设为
INFO或WARNING,避免日志刷屏,同时保留关键错误信息。 - 日志文件 :配合
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_DELAY 和 CONCURRENT_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_requests 或 parse 方法中给 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'] 计算耗时。
扩展的高级用法
- 动态配置 :通过
crawler.settings读取自定义配置项,实现开关、阈值等。 - 与 Pipeline 交互 :扩展可以访问
crawler.stats对象(Scrapy 内置统计),或通过crawler.engine获取调度器状态。 - 异步操作 :若需在扩展中执行异步任务(如发送 HTTP 请求),可使用
deferToThread或reactor.callLater。 - 错误处理:在信号处理函数中捕获异常,避免影响爬虫主流程。
常见扩展场景
- 自动暂停/恢复 :监听
spider_idle信号,当无待处理请求时自动暂停爬虫。 - 代理轮换 :在
request_scheduled中动态修改 Request 的代理。 - 数据备份 :在
spider_closed中将内存中的缓存数据写入磁盘。 - 邮件通知:爬虫异常时发送报警邮件。
总结
Scrapy 的配置体系是爬虫稳定运行的基石。通过合理调整并发、延时、UA、日志等核心参数,你可以在效率与礼貌之间找到平衡;而自定义扩展则赋予你无限可能------从简单的统计到复杂的自动化运维,都能通过几十行代码优雅实现。
记住:配置是骨架,扩展是血肉。掌握这两者,你就能从"会用 Scrapy"进阶到"驾驭 Scrapy"。