故障排查
爬虫不启动
问题 1: 找不到爬虫
错误信息:
ERROR: Spider not found: myspider
解决方案:
-
检查爬虫名称是否正确
-
检查爬虫文件是否在 spiders/ 目录下
-
检查爬虫类是否继承自 Spider
from crawlo import Spider # 确保导入正确
class MySpider(Spider): # 确保继承
name = 'myspider'
问题 2: 导入错误
错误信息:
ModuleNotFoundError: No module named 'xxx'
解决方案:
-
检查虚拟环境是否激活
# Windows
venv\Scripts\activate
# Linux/Mac
source venv/bin/activate
-
重新安装依赖
pip install -r requirements.txt
问题 3: 配置错误
错误信息:
RuntimeError: Invalid configuration
解决方案:
检查 settings.py 是否有语法错误:
python -m py_compile settings.py
请求超时
问题 1: 连接超时
错误信息:
TimeoutError: Connection timed out
解决方案:
-
检查网络连接
-
增加超时时间
# settings.py
DOWNLOAD_TIMEOUT = 30 # 30秒
-
使用代理
yield Request(url, meta={'proxy': 'http://proxy:8080'})
问题 2: 读取超时
错误信息:
TimeoutError: Read timed out
解决方案:
-
目标网站响应慢
# settings.py
DOWNLOAD_TIMEOUT = 60 # 增加到60秒
CONCURRENCY = 8 # 降低并发
-
使用浏览器渲染
yield Request(url, meta={'use_dynamic_loader': True})
数据未保存
问题 1: 文件为空
现象:运行后输出文件为空
原因:
- 爬虫没有提取到数据
- 选择器错误
解决方案:
-
调试选择器
async def parse(self, response):
# 打印 HTML 查看结构
print(response.text[:1000])
# 测试选择器
items = response.css('div.item').getall()
print(f"找到 {len(items)} 个元素")
-
检查 yield 语句
# 确保有 yield
async def parse(self, response):
yield {'title': 'test'} # 测试是否能输出
问题 2: 数据库未写入
现象:数据没有保存到数据库
解决方案:
-
检查数据库连接
# settings.py
MYSQL_HOST = 'localhost'
MYSQL_PORT = 3306
MYSQL_USER = 'root'
MYSQL_PASSWORD = 'password'
MYSQL_DATABASE = 'mydb'
-
检查 Pipeline 是否启用
# settings.py
PIPELINES = {
'crawlo.pipelines.MySQLPipeline': 300,
}
-
查看 Pipeline 日志
crawlo run myspider --log-level DEBUG
连接错误
问题 1: Redis 连接失败
错误信息:
redis.exceptions.ConnectionError: Error connecting to Redis
解决方案:
-
检查 Redis 是否运行
redis-cli ping # 应返回 PONG
-
检查连接配置
# settings.py
REDIS_HOST = 'localhost'
REDIS_PORT = 6379
REDIS_PASSWORD = '' # 如果有密码
-
启动 Redis
# Linux/Mac
redis-server
# Windows
redis-server.exe
问题 2: MySQL 连接失败
错误信息:
pymysql.err.OperationalError: (2003, "Can't connect to MySQL server")
解决方案:
-
检查 MySQL 是否运行
-
检查连接配置
# settings.py
MYSQL_HOST = 'localhost'
MYSQL_PORT = 3306
MYSQL_USER = 'root'
MYSQL_PASSWORD = 'password'
MYSQL_DATABASE = 'mydb'
-
创建数据库
CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
问题 3: MongoDB 连接失败
错误信息:
pymongo.errors.ServerSelectionTimeoutError
解决方案:
-
检查 MongoDB 是否运行
-
检查连接配置
# settings.py
MONGO_URI = 'mongodb://localhost:27017'
MONGO_DATABASE = 'mydb'
403 Forbidden
问题:被目标网站拒绝
错误信息:
解决方案:
-
设置 User-Agent
# settings.py
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ...'
-
使用代理
# settings.py
PROXY_ENABLED = True
PROXY_LIST = ['http://proxy1:8080']
-
使用浏览器渲染
yield Request(url, meta={'use_dynamic_loader': True})
-
启用 Cloudflare 绕过
# settings.py
CLOUDFLARE_BYPASS_ENABLED = True
500 Internal Server Error
问题:目标服务器错误
解决方案:
-
启用重试
# settings.py
RETRY_ENABLED = True
RETRY_TIMES = 3
-
添加延迟
# settings.py
DOWNLOAD_DELAY = 2.0
-
降低并发
# settings.py
CONCURRENCY = 4
内存溢出 (OOM)
问题:进程被系统杀死
解决方案:
-
限制队列大小
# settings.py
MEMORY_SCHEDULER_MAX_QUEUE_SIZE = 5000
-
启用背压
# settings.py
BACKPRESSURE_ENABLED = True
BACKPRESSURE_RATIO = 0.8
-
分批处理
# settings.py
BATCH_SIZE = 500
爬虫卡住不动
诊断步骤
-
查看日志
crawlo run myspider --log-level DEBUG
-
检查队列状态
# 在爬虫中
async def parse(self, response):
queue_size = await self.crawler.scheduler.queue.size()
self.logger.info(f"队列: {queue_size}")
-
检查是否有请求在等待
# settings.py
STATS_ENABLED = True
STATS_INTERVAL = 10
常见原因
| 原因 |
症状 |
解决方案 |
| 队列空了 |
无错误,爬虫退出 |
检查 start_urls |
| 所有请求失败 |
大量错误日志 |
检查代理、UA |
| 死锁 |
卡住不动 |
降低并发、增加超时 |
| 等待响应 |
日志停止更新 |
检查网络、增加超时 |
深度优先调度不生效
问题:设置了 DEPTH_PRIORITY=1 但详情页没有优先处理
现象:
- 列表页和详情页的 priority 值相同
- 首个 Item 产出时间极慢(需要等所有列表页处理完才处理详情页)
- 调试日志显示子请求 depth 与父请求相同(如都是 depth=1)
原因分析:
depth 传播由 Engine 的 _handle_spider_output 统一管理。如果中间件或工具函数提前向 request.meta 注入了 depth,Engine 的 if 'depth' not in spider_output.meta 检查会被跳过,导致子请求 depth 值错误。
诊断步骤:
-
开启 DEBUG 日志,检查 depth 传播:
# settings.py
LOG_LEVEL = 'DEBUG'
-
在日志中搜索关键信息:
[产出] 子请求 depth=1 ← 如果子请求 depth 与父请求相同,说明 depth 传播失效
[set_request] had_depth=True → depth=1 ← depth 已存在但值错误
-
正确的日志应显示:
[产出] 子请求 depth=2 ← 子请求 depth = parent_depth + 1
[set_request] had_depth=True → depth=2, priority: 0 → -2 ← 深度优先生效
解决方案:
检查是否有中间件或工具函数提前设置了 request.meta['depth'],确保 depth 仅由 Engine 传播:
# ❌ 错误:中间件或工具函数不应提前注入 depth
def some_middleware(request, spider):
request.meta.setdefault('depth', response.meta.get('depth', 0)) # 会导致 depth 传播失效
# ✅ 正确:让 Engine 自动传播 depth
def some_middleware(request, spider):
# 不要设置 depth,Engine 会自动处理
pass
详见 设计缺陷修复记录。
Ctrl+C 无法停止爬虫
问题:按 Ctrl+C 后爬虫继续运行
解决方案:
确保使用正确的关闭方法:
# settings.py
CLOSE_SPIDER_ON_SIGNAL = True
查看 爬虫生命周期 了解关闭机制。
日志不输出
问题:运行时看不到日志
解决方案:
-
检查日志级别
# settings.py
LOG_LEVEL = 'DEBUG' # 最详细
-
检查日志输出
# settings.py
LOG_FILE = 'spider.log' # 输出到文件
LOG_TO_CONSOLE = True # 同时输出到控制台
还有其他问题? 查看 使用指南 或提交 GitHub Issue。