Skip to main content

Crawlo: A high-performance asynchronous Python web crawling framework with distributed support.。

Project description

Crawlo Logo

Crawlo

一个基于 asyncio 的现代化、高性能 Python 异步爬虫框架。

核心特性架构安装配置模式文档

核心特性

  • 🚀 高性能异步架构:基于 asyncio 和 aiohttp,充分利用异步 I/O 提升爬取效率
  • 🎯 智能调度系统:优先级队列、并发控制、自动重试、智能限速
  • 🔄 灵活的配置模式
    • Standalone 模式:单机开发测试,使用内存队列
    • Distributed 模式:多节点分布式部署,严格要求 Redis(不允许降级)
    • Auto 模式:智能检测 Redis 可用性,自动选择最佳配置(推荐)
  • 📦 丰富的组件生态
    • 内置 Redis 和 MongoDB 支持
    • MySQL 异步连接池(基于 asyncmy 和 aiomysql 双驱动支持)
    • 连接池健康检查与自动修复机制
    • 多种过滤器和去重管道(Memory/Redis)
    • 代理中间件支持(简单代理/动态代理)
    • 多种下载器(aiohttp、httpx、curl-cffi)
  • 🛠 开发友好
    • 类 Scrapy 的项目结构和 API 设计
    • 配置工厂模式(CrawloConfig.auto()
    • 自动爬虫发现机制
    • 完善的日志系统

项目架构

Crawlo 框架采用模块化设计,核心组件包括:

Crawlo 框架架构图

  • Engine:核心引擎,协调各个组件工作
  • Scheduler:调度器,管理请求队列和去重
  • Downloader:下载器,支持多种 HTTP 客户端
  • Spider:爬虫基类,定义数据提取逻辑
  • Pipeline:数据管道,处理和存储数据
  • Middleware:中间件,处理请求和响应

Crawlo 数据流图

示例项目

查看 examples/ 目录下的完整示例项目:

  • ofweek_standalone - Auto 模式示例(智能检测)
  • ofweek_spider - Auto 模式示例
  • ofweek_distributed - Distributed 模式示例(严格分布式)

安装

# 基础安装
pip install crawlo

配置模式详解

⚠️ 重要:配置模式的选择直接影响爬虫的运行方式、性能和可靠性,请仔细阅读本节内容。

Crawlo 提供三种配置模式,满足不同场景需求:

三种模式对比

配置项 Standalone Distributed Auto
RUN_MODE standalone distributed auto
队列类型 内存队列 Redis 队列 自动检测
Redis 要求 不需要 必需 可选
Redis 不可用时 N/A 🚫 报错退出 ✅ 降级到内存
配置自动更新 ❌ 否 ❌ 否 ✅ 是
过滤器 Memory Redis Redis/Memory
去重管道 Memory Redis Redis/Memory
适用场景 开发测试 多节点部署 生产环境
并发数默认值 8 16 12
推荐指数 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐

1. Auto 模式(推荐)

智能检测,自动适配,推荐用于生产环境。

``python from crawlo.config import CrawloConfig

config = CrawloConfig.auto( project_name='myproject', concurrency=12, download_delay=1.0 ) locals().update(config.to_dict())


**运行机制**:
- 配置阶段不依赖 Redis
- 运行时才检测 Redis 可用性
- Redis 可用 → 使用 `RedisPriorityQueue` + `AioRedisFilter`
- Redis 不可用 → 降级到 `MemoryQueue` + `MemoryFilter`
- 自动更新配置(`QUEUE_TYPE`、`FILTER_CLASS`、`DEFAULT_DEDUP_PIPELINE`)

**优势**:
- ✅ 开发环境无需配置 Redis,直接启动
- ✅ 生产环境 Redis 故障时自动降级,保证系统可用性
- ✅ 同一份代码可在不同环境运行,无需修改配置
- ✅ 最佳的灵活性和可靠性

**适用场景**:
- 生产环境部署(首选)
- 需要在多种环境运行的项目
- 希望系统具备容错能力

### 2. Standalone 模式

**单机模式,适合开发测试和中小规模爬取。**

``python
config = CrawloConfig.standalone(
    project_name='myproject',
    concurrency=8
)
locals().update(config.to_dict())

运行机制

  • 固定使用 MemoryQueue(内存队列)
  • 固定使用 MemoryFilter(内存过滤器)
  • 固定使用 MemoryDedupPipeline(内存去重)
  • 不进行 Redis 检测
  • 配置不会自动更新

优势

  • ✅ 无需任何外部依赖
  • ✅ 启动速度快
  • ✅ 适合快速开发调试

限制

  • ❌ 不支持分布式部署
  • ❌ 重启后队列数据丢失
  • ❌ 不适合大规模数据采集

适用场景

  • 本地开发调试
  • 学习框架特性
  • 中小规模数据采集(< 10万条)
  • 单机运行的简单爬虫

3. Distributed 模式

分布式模式,严格要求 Redis 可用,适合多节点协同工作。

``python config = CrawloConfig.distributed( project_name='myproject', redis_host='redis.example.com', redis_port=6379, redis_password='your_password', concurrency=16 ) locals().update(config.to_dict())


**运行机制**:
- 必须使用 `RedisPriorityQueue`
- 必须使用 `AioRedisFilter`
- 必须使用 `RedisDedupPipeline`
- 启动时强制检查 Redis 连接
- **Redis 不可用时抛出 `RuntimeError` 并退出(不允许降级)**

**为什么要严格要求 Redis?**

1. **数据一致性**:防止不同节点使用不同的队列类型
2. **去重有效性**:确保多节点间的去重功能正常工作
3. **任务分配**:防止任务被重复执行
4. **问题早发现**:启动失败比运行时失败更容易发现和修复
5. **明确的意图**:分布式模式就应该是分布式的,不应该静默降级

**Redis 不可用时的错误信息**:

$ crawlo run my_spider

2025-10-25 22:00:00 - [queue_manager] - ERROR: Distributed 模式要求 Redis 可用,但无法连接到 Redis 服务器。 错误信息: Connection refused Redis URL: redis://127.0.0.1:6379/0 请检查:

  1. Redis 服务是否正在运行
  2. Redis 连接配置是否正确
  3. 网络连接是否正常

RuntimeError: Distributed 模式要求 Redis 可用,但无法连接到 Redis 服务器。


**优势**:
- ✅ 支持多节点协同爬取
- ✅ 数据持久化,重启后可继续
- ✅ 严格的分布式一致性保证
- ✅ 适合大规模数据采集

**适用场景**:
- 多服务器协同采集
- 大规模数据采集(> 百万条)
- 需要严格保证分布式一致性
- 生产环境多节点部署

### 模式选择建议

| 场景 | 推荐模式 | 原因 |
|------|---------|------|
| 生产环境(单节点或多节点) | **Auto** | 自动适配,容错能力强 |
| 开发环境 | **Standalone** 或 **Auto** | 无需配置 Redis |
| 严格的多节点分布式部署 | **Distributed** | 保证分布式一致性 |
| 学习和测试 | **Standalone** | 最简单,无依赖 |
| 中小规模爬取 | **Standalone** 或 **Auto** | 简单高效 |
| 大规模爬取 | **Auto** 或 **Distributed** | 性能和可靠性 |

> 📖 **完整文档**:更多详细信息请参考 [配置模式完全指南](docs/tutorials/configuration_modes.md)

## Redis 数据结构说明

在使用 Distributed 模式或 Auto 模式且 Redis 可用时,Crawlo 框架会在 Redis 中创建以下数据结构用于管理和跟踪爬虫状态:

### 核心 Redis Keys

1. **`{project_name}:filter:fingerprint`** - 请求去重过滤器
   - 类型:Redis Set
   - 用途:存储已处理请求的指纹,避免重复抓取相同URL
   - 示例:`crawlo:ofweek_standalone:filter:fingerprint`

2. **`{project_name}:item:fingerprint`** - 数据项去重集合
   - 类型:Redis Set
   - 用途:存储已处理数据项的指纹,避免重复处理相同的数据
   - 示例:`crawlo:ofweek_standalone:item:fingerprint`

3. **`{project_name}:queue:requests`** - 主请求队列
   - 类型:Redis Sorted Set
   - 用途:存储待处理的爬虫请求,按优先级排序
   - 示例:`crawlo:ofweek_standalone:queue:requests`

4. **`{project_name}:queue:requests:data`** - 主请求队列数据
   - 类型:Redis Hash
   - 用途:保存请求队列中每个请求的详细序列化数据
   - 示例:`crawlo:ofweek_standalone:queue:requests:data`

### 数据核验方法

在爬虫采集完成后,您可以使用这些 Redis key 来核验数据和监控爬虫状态:

```bash
# 连接到 Redis
redis-cli

# 查看请求去重数量(已处理的唯一URL数)
SCARD crawlo:ofweek_standalone:filter:fingerprint

# 查看数据项去重数量(已处理的唯一数据项数)
SCARD crawlo:ofweek_standalone:item:fingerprint

# 查看待处理队列长度
ZCARD crawlo:ofweek_standalone:queue:requests

# 获取部分指纹数据进行检查
SMEMBERS crawlo:ofweek_standalone:filter:fingerprint LIMIT 10

# 获取队列中的请求信息
ZRANGE crawlo:ofweek_standalone:queue:requests 0 -1 WITHSCORES LIMIT 10

注意事项

  1. 数据清理:爬虫任务完成后,建议清理这些 Redis keys 以释放内存:

    DEL crawlo:ofweek_standalone:filter:fingerprint
    DEL crawlo:ofweek_standalone:item:fingerprint
    DEL crawlo:ofweek_standalone:queue:requests
    DEL crawlo:ofweek_standalone:queue:requests:data
    
  2. 命名空间隔离:不同项目使用不同的 {project_name} 前缀,确保数据隔离。对于同一项目下的不同爬虫,还可以通过 {spider_name} 进一步区分,确保更细粒度的数据隔离。

  3. 持久化考虑:如果需要持久化这些数据,确保 Redis 配置了合适的持久化策略

配置优先级

Crawlo 框架支持多层级的配置系统,了解配置优先级对于正确使用框架至关重要。

配置来源与优先级

低到高的优先级顺序:

1. default_settings.py (框架默认配置)                    ⭐
   ↓
2. 环境变量 (CRAWLO_*)                                   ⭐⭐
   (在 default_settings.py 中通过 EnvConfigManager 读取)
   ↓
3. 用户 settings.py (项目配置文件)                       ⭐⭐⭐
   ↓
4. Spider.custom_settings (Spider 自定义配置)            ⭐⭐⭐⭐
   ↓
5. 运行时 settings 参数 (crawl() 传入的配置)             ⭐⭐⭐⭐⭐

环境变量配置

所有环境变量都使用 CRAWLO_ 前缀:

# 基础配置
export CRAWLO_MODE=auto                    # 运行模式
export CRAWLO_PROJECT_NAME=myproject       # 项目名称
export CRAWLO_CONCURRENCY=16               # 并发数

# Redis 配置
export CRAWLO_REDIS_HOST=127.0.0.1         # Redis 主机
export CRAWLO_REDIS_PORT=6379              # Redis 端口
export CRAWLO_REDIS_PASSWORD=your_password # Redis 密码
export CRAWLO_REDIS_DB=0                   # Redis 数据库

配置合并策略

普通配置(如 CONCURRENCY):采用覆盖策略

# 假设各处都有定义
default_settings.py:  8   
环境变量:  12  
settings.py:  16  
Spider.custom_settings:  24  
crawl(settings={...}):  32   最终值 = 32

列表配置(如 MIDDLEWARESPIPELINESEXTENSIONS):采用合并策略

# default_settings.py
PIPELINES = {
    'crawlo.pipelines.console_pipeline.ConsolePipeline': 500,
}

# settings.py
PIPELINES = {
    'myproject.pipelines.MySQLPipeline': 600,
}

# 最终结果(合并)
PIPELINES = {
    'crawlo.pipelines.console_pipeline.ConsolePipeline': 500,  # 保留默认
    'myproject.pipelines.MySQLPipeline': 600,                   # 追加用户
}

Spider 级别配置

在 Spider 类中可以覆盖项目配置:

class MySpider(Spider):
    name = 'myspider'
    
    custom_settings = {
        'CONCURRENCY': 32,           # 覆盖项目配置
        'DOWNLOAD_DELAY': 2.0,       # 覆盖项目配置
        'PIPELINES': [               # 会与默认管道合并
            'myproject.pipelines.SpecialPipeline',
        ]
    }

运行时动态配置

from crawlo import CrawlerProcess

process = CrawlerProcess()
await process.crawl(
    MySpider,
    settings={
        'CONCURRENCY': 64,        # 最高优先级
        'DOWNLOAD_DELAY': 0.1,
    }
)

⚠️ 常见陷阱

陷阱1:环境变量被项目配置覆盖

# 环境变量
export CRAWLO_REDIS_HOST=192.168.1.100

# settings.py(这会覆盖环境变量!)
REDIS_HOST = 'localhost'  # ❌ 会覆盖环境变量

# 解决方案:不在 settings.py 中重复设置,或使用 CrawloConfig.auto()

陷阱2:误以为字典配置会被清空

# settings.py
PIPELINES = {
    'myproject.pipelines.MySQLPipeline': 600,
}

# 实际结果(默认管道会被保留并合并)
PIPELINES = {
    'crawlo.pipelines.console_pipeline.ConsolePipeline': 500,  # 默认保留
    'myproject.pipelines.MySQLPipeline': 600,                   # 用户追加
}

# 如果想完全替换,需要先清空
PIPELINES = {}  # 清空
PIPELINES['myproject.pipelines.MySQLPipeline'] = 600

📖 详细文档:完整的配置优先级说明请参考 配置优先级详解

中间件优先级策略

在 Crawlo 框架中,中间件的执行顺序由优先级数值决定。请求阶段按数值从小到大执行,响应阶段按数值从大到小执行(LIFO 模式)。

1. 优先级设计原则

采用双向对称设计

  • 请求阶段(process_request):数值越小,越先执行
  • 响应阶段(process_response):数值越大,越先执行

这种设计确保:

  • 请求处理最早执行的中间件,在响应处理时最后执行(类似洋葱模型)
  • 符合中间件的天然依赖关系(如:先添加请求头,后处理响应)

2. 默认中间件优先级

MIDDLEWARES = {
    # 请求阶段(小 → 大)
    'crawlo.middleware.request_ignore.RequestIgnoreMiddleware': 100,  # 1. 忽略无效请求
    'crawlo.middleware.download_delay.DownloadDelayMiddleware': 200,  # 2. 下载延迟控制
    'crawlo.middleware.default_header.DefaultHeaderMiddleware': 300,  # 3. 添加默认请求头
    'crawlo.middleware.offsite.OffsiteMiddleware': 400,               # 4. 站外请求过滤
    
    # 响应阶段(大 → 小)
    'crawlo.middleware.response_filter.ResponseFilterMiddleware': 700, # 5. 响应过滤
    'crawlo.middleware.response_code.ResponseCodeMiddleware': 650,     # 6. 状态码处理
    'crawlo.middleware.retry.RetryMiddleware': 600,                    # 7. 请求重试
}

3. 内置优先级常量

框架提供了语义化常量供用户使用:

from crawlo.utils.priority import MiddlewarePriority

# 可用常量
MiddlewarePriority.CUSTOM = 500          # 自定义中间件默认优先级
MiddlewarePriority.CUSTOM_REQUEST = 450  # 自定义请求处理中间件
MiddlewarePriority.CUSTOM_RESPONSE = 550 # 自定义响应处理中间件

4. 用户自定义中间件优先级建议

  • 请求处理类

    • 安全/认证:100-200
    • 请求过滤/验证:200-300
    • 请求头/代理设置:300-400
    • 通用请求处理:400-500
  • 响应处理类

    • 通用响应处理:500-600
    • 重试/恢复:600-650
    • 响应验证/解析:650-700
    • 响应后处理:700-800

5. 使用示例

from crawlo.utils.priority import MiddlewarePriority

MIDDLEWARES = {
    # 使用语义化常量
    'myproject.middleware.AuthMiddleware': MiddlewarePriority.CUSTOM_REQUEST,
    'myproject.middleware.DataParseMiddleware': MiddlewarePriority.CUSTOM_RESPONSE,
    
    # 或直接使用数值
    'myproject.middleware.CustomMiddleware': 500,
}

6. 优先级设置原则

  1. 过滤器优先:能快速拒绝无效请求的中间件应具有较小数值(请求阶段先执行)
  2. 依赖关系:如果中间件 A 的输出是 B 的输入,A 的数值应小于 B
  3. 对称性:请求阶段数值小的中间件,在响应阶段会最后执行
  4. 间隔预留:建议以 50-100 为间隔,方便后续插入新中间件

💡 提示OffsiteMiddleware 只有在配置了 ALLOWED_DOMAINS 时才会启用,否则会因 NotConfiguredError 而被禁用

快速开始

1. 创建项目

# 创建新项目
crawlo startproject myproject
cd myproject

# 创建爬虫
crawlo genspider example example.com

2. 配置项目(推荐使用 Auto 模式)

# myproject/settings.py
from crawlo.config import CrawloConfig

# 使用 Auto 模式:智能检测 Redis,自动选择最佳配置
config = CrawloConfig.auto(
    project_name='myproject',
    concurrency=12,          # 并发数
    download_delay=1.0       # 下载延迟(秒)
)

# 将配置应用到当前模块
locals().update(config.to_dict())

# 爬虫模块配置
SPIDER_MODULES = ['myproject.spiders']

# 日志配置
LOG_LEVEL = 'INFO'
LOG_FILE = 'logs/myproject.log'

# 可选:添加数据管道(注意:现在是字典格式)
# PIPELINES = {
#     'crawlo.pipelines.mysql_pipeline.MySQLPipeline': 500,
# }

# 可选:Redis 配置(Auto 模式会自动检测)
# REDIS_HOST = '127.0.0.1'
# REDIS_PORT = 6379

其他配置模式:

# Standalone 模式:单机开发测试
config = CrawloConfig.standalone(
    project_name='myproject',
    concurrency=8
)

# Distributed 模式:多节点分布式(必须配置 Redis)
config = CrawloConfig.distributed(
    project_name='myproject',
    redis_host='redis.example.com',
    redis_port=6379,
    redis_password='your_password',
    concurrency=16
)

3. 编写爬虫

# myproject/spiders/example.py
from crawlo import Spider
from crawlo.http import Request

class ExampleSpider(Spider):
    name = 'example'
    start_urls = ['https://example.com']
    
    async def parse(self, response):
        # 提取数据
        title = response.css('h1::text').get()
        
        # 返回数据
        yield {
            'title': title,
            'url': response.url
        }
        
        # 跟进链接
        for href in response.css('a::attr(href)').getall():
            yield Request(
                url=response.urljoin(href),
                callback=self.parse
            )

4. 运行爬虫

# 运行指定爬虫
crawlo run example

# 指定日志级别
crawlo run example --log-level DEBUG

通知系统

Crawlo 提供了完善的多平台通知系统,支持钉钉、飞书、企业微信、邮件和短信通知。

📋 配置说明

settings.py 中配置通知系统:

# 启用通知系统
NOTIFICATION_ENABLED = True
NOTIFICATION_CHANNELS = ['dingtalk']  # 可选: dingtalk, feishu, wecom, email, sms

# 钉钉通知配置
DINGTALK_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN"
DINGTALK_SECRET = "YOUR_SECRET"
DINGTALK_KEYWORDS = ["爬虫"]  # 关键词验证
DINGTALK_AT_MOBILES = ["15361276730"]  # @特定手机号
DINGTALK_IS_AT_ALL = False  # 是否@所有人

# 飞书/企业微信配置(类似)
FEISHU_WEBHOOK = "YOUR_FEISHU_WEBHOOK"
WECOM_WEBHOOK = "YOUR_WECOM_WEBHOOK"

🚀 基础使用

from crawlo.bot.handlers import send_crawler_status, send_crawler_alert, send_crawler_progress
from crawlo.bot.models import ChannelType

# 发送状态通知
await send_crawler_status(
    title="【状态】爬虫启动",
    content="爬虫任务已启动,开始抓取数据...",
    channel=ChannelType.DINGTALK
)

# 发送进度通知
await send_crawler_progress(
    title="【进度】数据抓取",
    content="已完成 50% 的数据抓取任务",
    channel=ChannelType.DINGTALK
)

# 发送告警通知
await send_crawler_alert(
    title="【告警】网络异常",
    content="检测到网络连接不稳定,部分请求失败",
    channel=ChannelType.DINGTALK
)

📊 使用建议

推荐通知节点:

  • 爬虫启动时 - 发送状态通知
  • 关键里程碑 - 发送进度通知(如每100条数据)
  • 异常情况 - 立即发送告警通知
  • 任务完成时 - 发送总结通知

@ 功能使用:

# @ 特定手机号
DINGTALK_AT_MOBILES = ["15361276730"]

# @ 所有人
DINGTALK_IS_AT_ALL = True

重试机制:

NOTIFICATION_RETRY_ENABLED = True
NOTIFICATION_RETRY_TIMES = 3
NOTIFICATION_RETRY_DELAY = 5  # 秒

💡 详细使用指南请参考 docs/notification_guide.md

核心功能

Response 对象

Crawlo 的 Response 对象提供了强大的网页处理能力:

1. 智能编码检测

# 自动检测并正确解码页面内容
# 优先级:Content-Type → HTML meta → chardet → utf-8
response.text      # 已正确解码的文本
response.encoding  # 检测到的编码

2. CSS/XPath 选择器

# CSS 选择器(推荐)
title = response.css('h1::text').get()
links = response.css('a::attr(href)').getall()

# XPath 选择器
title = response.xpath('//title/text()').get()
links = response.xpath('//a/@href').getall()

# 支持默认值
title = response.css('h1::text').get(default='无标题')

3. URL 处理

response.url          # 自动规范化(移除 fragment)
response.original_url # 保留原始 URL

# 智能 URL 拼接
response.urljoin('/path')           # 绝对路径
response.urljoin('../path')         # 相对路径
response.urljoin('//cdn.com/img')   # 协议相对路径

4. 便捷提取方法

# 提取单个/多个元素文本
title = response.extract_text('h1')
paragraphs = response.extract_texts('.content p')

# 提取单个/多个元素属性
link = response.extract_attr('a', 'href')
all_links = response.extract_attrs('a', 'href')

MySQLHelper 数据库操作工具

Crawlo 提供了 MySQLHelper 工具类,用于在 Spider 中进行数据库操作(如数据去重检查)。

1. 基本用法

from crawlo.utils.mysql_helper import get_mysql_helper

class MySpider(Spider):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.db_helper = None
    
    async def parse_detail(self, response):
        # 首次使用时初始化 MySQLHelper
        if self.db_helper is None:
            # 方式1: 直接传入 spider,自动获取配置(推荐)
            self.db_helper = await get_mysql_helper(spider=self)
            # 方式2: 手动传入 settings
            # self.db_helper = await get_mysql_helper(self.crawler.settings)
        
        # 检查数据是否存在
        table_name = self.crawler.settings.get('MYSQL_TABLE', 'my_table')
        exists = await self.db_helper.exists(table_name, {"url": response.url})
        
        if exists:
            self.logger.info(f"数据已存在,跳过:{response.url}")
            return
        
        # 继续处理...

2. 配置说明

方式一:通过 custom_settings 配置(推荐)

class MySpider(Spider):
    name = 'my_spider'
    
    # 在 spider 中配置表名
    custom_settings = {
        'MYSQL_TABLE': 'my_table',  # 数据表名
    }

方式二:通过 settings.py 全局配置

# settings.py
MYSQL_TABLE = 'my_table'

3. 配置优先级

spider.custom_settings > settings.py > 默认值

4. 连接池复用

  • MySQLHelper 每次调用会创建新实例
  • 但连接池由 MySQLConnectionPoolManager 统一管理
  • 相同配置(host:port:db)的请求会复用同一个连接池

5. API 参考

方法 说明
get_mysql_helper(spider=self) 获取 MySQLHelper 实例
helper.exists(table, conditions) 检查数据是否存在
helper.insert(table, data) 插入单条数据
helper.batch_insert(table, data_list) 批量插入数据

配置工厂模式

Crawlo 提供了便捷的配置工厂方法,无需手动配置繁琐的参数:

from crawlo.config import CrawloConfig

# Auto 模式(推荐):智能检测,自动适配
config = CrawloConfig.auto(
    project_name='myproject',
    concurrency=12,
    download_delay=1.0
)

# Standalone 模式:单机开发
config = CrawloConfig.standalone(
    project_name='myproject',
    concurrency=8
)

# Distributed 模式:严格分布式
config = CrawloConfig.distributed(
    project_name='myproject',
    redis_host='localhost',
    redis_port=6379,
    concurrency=16
)

# 应用到 settings.py
locals().update(config.to_dict())

三种模式的核心区别

  • Auto:智能检测 Redis,自动选择最佳配置,推荐用于生产环境
  • Standalone:固定使用内存队列,适合开发测试,无外部依赖
  • Distributed:严格要求 Redis,不允许降级,保证分布式一致性

💡 详细配置说明请查看前面的 配置模式详解 章节

定时任务功能

Crawlo 提供了内置的定时任务调度功能,支持灵活的周期性爬虫执行:

1. 启用定时任务

在项目配置文件中启用并配置定时任务:

# settings.py

# 启用定时任务 - 默认关闭
SCHEDULER_ENABLED = True

# 定时任务配置
SCHEDULER_JOBS = [
    {
        'spider': 'myproject.spiders.my_spider',  # 爬虫名称(对应spider的name属性)
        'cron': '*/30 * * * *',       # 每30分钟执行一次
        'enabled': True,              # 任务启用状态
        'priority': 10,               # 任务优先级
        'max_retries': 3,             # 最大重试次数
        'retry_delay': 60,            # 重试延迟(秒)
        'args': {},                  # 传递给爬虫的参数
        'kwargs': {}                  # 传递给爬虫的额外参数
    },
    {
        'spider': 'myproject.spiders.another_spider',  # 另一个爬虫
        'cron': '0 2 * * *',         # 每天凌晨2点执行
        'enabled': True,              # 任务启用状态
        'priority': 20,               # 任务优先级
        'max_retries': 2,             # 最大重试次数
        'retry_delay': 120,           # 重试延迟(秒)
        'args': {'daily': True},      # 传递给爬虫的参数
        'kwargs': {}                  # 传递给爬虫的额外参数
    }
]

# 关键配置参数(用户可能需要调整)
SCHEDULER_CHECK_INTERVAL = 1           # 调度器检查间隔(秒)
SCHEDULER_MAX_CONCURRENT = 3           # 最大并发任务数
SCHEDULER_JOB_TIMEOUT = 3600           # 单个任务超时时间(秒)
SCHEDULER_RESOURCE_MONITOR_ENABLED = True  # 是否启用资源监控
SCHEDULER_RESOURCE_CHECK_INTERVAL = 300    # 资源检查间隔(秒)
SCHEDULER_RESOURCE_LEAK_THRESHOLD = 3600   # 资源泄露检测阈值(秒)

2. 运行定时任务

有两种方式运行定时任务:

方法一:使用命令行

# 启动定时任务调度器(在项目目录下运行)
crawlo schedule

方法二:使用项目模板生成的 run.py 文件

# 启动定时任务模式
python run.py --schedule

# 正常运行单次爬虫
python run.py

3. Cron 表达式说明

定时任务使用标准的 Cron 表达式格式:分钟 小时 日 月 星期

常见表达式示例:

  • */5 * * * * - 每5分钟执行一次
  • 0 */2 * * * - 每2小时执行一次
  • 30 9 * * * - 每天上午9:30执行
  • 0 2 * * 0 - 每周日凌晨2点执行
  • 0 1 1 * * - 每月1号凌晨1点执行

4. 资源监控与管理

定时任务系统集成了资源监控功能,可自动检测和管理资源泄露,确保长时间稳定运行。调度器还支持并发控制和任务超时管理,防止任务堆积和资源耗尽。

日志系统

Crawlo 提供了完善的日志系统,支持控制台和文件双输出:

from crawlo.logging import get_logger

logger = get_logger(__name__)

logger.debug('调试信息')
logger.info('普通信息')
logger.warning('警告信息')
logger.error('错误信息')

日志配置:

# settings.py
LOG_LEVEL = 'INFO'          # DEBUG, INFO, WARNING, ERROR, CRITICAL
LOG_FILE = 'logs/spider.log'
LOG_ENCODING = 'utf-8'      # 明确指定日志文件编码
STATS_DUMP = True           # 是否输出统计信息

高级功能:

from crawlo.logging import configure_logging

# 分别配置控制台和文件日志级别
configure_logging(
    LOG_LEVEL='INFO',
    LOG_CONSOLE_LEVEL='WARNING',  # 控制台只显示 WARNING 及以上
    LOG_FILE_LEVEL='DEBUG',       # 文件记录 DEBUG 及以上
    LOG_FILE='logs/app.log',
    LOG_MAX_BYTES=10*1024*1024,   # 10MB
    LOG_BACKUP_COUNT=5
)

爬虫自动发现

Crawlo 支持自动发现爬虫,无需手动导入:

# 自动发现并运行(推荐)
crawlo run spider_name

# 指定文件路径运行
crawlo run -f path/to/spider.py -s SpiderClassName

框架会自动在 SPIDER_MODULES 配置的模块中查找爬虫。

跨平台支持

Crawlo 在 Windows、macOS、Linux 上均可无缝运行:

  • Windows:自动使用 ProactorEventLoop,正确处理控制台编码
  • macOS/Linux:使用默认的 SelectorEventLoop
  • 兼容不同平台的路径格式

💡 Windows 用户提示:框架默认已禁用日志轮转功能以避免文件锁定问题。如需启用日志轮转,建议安装 concurrent-log-handler

pip install concurrent-log-handler

然后在 settings.py 中设置:

LOG_MAX_BYTES = 10 * 1024 * 1024  # 10MB
LOG_BACKUP_COUNT = 5

Crawlo 核心架构图

文档

完整文档请查看 docs/ 目录:

📚 核心教程

🔧 核心模块

📦 功能模块

🛠 命令行工具

🚀 高级主题

📝 性能优化报告

🎯 中间件指南

📖 API 参考


在线文档

本地构建文档

mkdocs serve
# 浏览器访问 http://localhost:8000

常见问题

1. 如何选择配置模式?

  • 开发测试:使用 CrawloConfig.standalone()
  • 生产环境:使用 CrawloConfig.auto()(推荐)
  • 多节点部署:使用 CrawloConfig.distributed()

2. Distributed 模式 Redis 不可用怎么办?

Distributed 模式严格要求 Redis,不可用时会抛出 RuntimeError 并退出。这是为了保证分布式一致性和数据安全。

如果希望 Redis 不可用时自动降级,请使用 Auto 模式

3. Auto 模式如何工作?

Auto 模式在运行时智能检测:

  • Redis 可用 → 使用 RedisPriorityQueue + AioRedisFilter
  • Redis 不可用 → 降级到 MemoryQueue + MemoryFilter

详见 配置模式完全指南

4. 如何启用 MySQL 或 MongoDB 支持?

# settings.py

PIPELINES = {
    'crawlo.pipelines.mysql_pipeline.MySQLPipeline': 500,  # MySQL
    # 或
    'crawlo.pipelines.mongo_pipeline.MongoDBPipeline': 500,       # MongoDB
}

# MySQL 配置
MYSQL_HOST = '127.0.0.1'
MYSQL_USER = 'root'
MYSQL_PASSWORD = 'password'
MYSQL_DB = 'mydb'
MYSQL_TABLE = 'items'

# MySQL 冲突处理策略(三者互斥,按优先级生效)
MYSQL_UPDATE_COLUMNS = ('updated',)  # 优先级最高:主键冲突时更新指定列,使用 ON DUPLICATE KEY UPDATE
MYSQL_AUTO_UPDATE = False           # 优先级中等:是否使用 REPLACE INTO(完全覆盖已存在记录)
MYSQL_INSERT_IGNORE = False         # 优先级最低:是否使用 INSERT IGNORE(忽略重复数据)

# 批量插入配置
MYSQL_USE_BATCH = True             # 是否使用批量插入提高性能
MYSQL_BATCH_SIZE = 100              # 批量插入大小
MYSQL_BATCH_TIMEOUT = 90            # 批量操作超时时间(秒)

# MySQL 连接池配置
MYSQL_POOL_MIN = 8                  # 最小连接数
MYSQL_POOL_MAX = 30                 # 最大连接数
MYSQL_HEALTH_CHECK_INTERVAL = 300.0 # 连接池健康检查间隔(秒),默认5分钟
MYSQL_POOL_REPAIR_ATTEMPTS = 3      # 连接池修复尝试次数,默认3次

# MongoDB 配置
MONGO_URI = 'mongodb://localhost:27017'
MONGO_DATABASE = 'mydb'
MONGO_COLLECTION = 'items'

MySQL 冲突处理策略说明:

Crawlo 的 MySQL 管道支持三种冲突处理策略,它们按照以下优先级顺序生效,高优先级会覆盖低优先级

  1. MYSQL_UPDATE_COLUMNS(最高优先级)

    • 设置此项时,使用 INSERT ... ON DUPLICATE KEY UPDATE 语句
    • 当主键或唯一索引冲突时,仅更新指定的列
    • 示例:MYSQL_UPDATE_COLUMNS = ('updated', 'modified')
  2. MYSQL_AUTO_UPDATE(中等优先级)

    • MYSQL_UPDATE_COLUMNS 未设置时生效
    • 使用 REPLACE INTO 语句,完全替换已存在的记录
    • 设置为 True 时启用
  3. MYSQL_INSERT_IGNORE(最低优先级)

    • 当前两个选项都未设置时生效
    • 使用 INSERT IGNORE 语句,遇到冲突时忽略重复数据
    • 设置为 True 时启用

注意:这三个参数是互斥的,只会应用优先级最高的那个设置。

5. 如何使用代理?

# settings.py

# 简单代理列表
PROXY_LIST = [
    "http://proxy1:8080",
    "http://proxy2:8080"
]

# 或使用动态代理 API
PROXY_API_URL = "http://your-proxy-api.com/get-proxy"

学习路径

如果您是 Crawlo 的新用户,建议按以下顺序学习:

  1. 入门 - 阅读快速开始指南,运行第一个示例
  2. 配置模式 - 学习三种配置模式,选择适合的模式(配置模式指南
  3. 核心概念 - 了解框架架构和基本概念
  4. 核心模块 - 深入学习引擎、调度器、处理器等核嘿组件
  5. 功能模块 - 根据需求学习下载器、队列、过滤器等模块
  6. 高级主题 - 掌握分布式部署、性能优化等高级功能

贡献

欢迎贡献!如果您想为 Crawlo 做出贡献,请访问我们的 GitHub 仓库

  1. Fork Crawlo 仓库
  2. 创建功能分支 (git checkout -b feature/AmazingFeature)
  3. 提交您的更改 (git commit -m 'Add some AmazingFeature')
  4. 推送到分支 (git push origin feature/AmazingFeature)
  5. 发起 Pull Request

许可证

MIT License - 详见 LICENSE 文件

变更日志

v1.6.0 (2026-04-07)

  • 中间件优先级重构:采用双向对称设计

    • 请求阶段:数值越小,越先执行
    • 响应阶段:数值越大,越先执行(LIFO 模式)
    • 提供语义化常量:MiddlewarePriority.CUSTOM, CUSTOM_REQUEST, CUSTOM_RESPONSE
    • 详见 中间件优先级策略
  • 配置格式统一MIDDLEWARESPIPELINESEXTENSIONS 统一使用字典格式

    • 旧格式:PIPELINES = ['pipeline1', 'pipeline2']
    • 新格式:PIPELINES = {'pipeline1': 500, 'pipeline2': 600}
    • 支持配置优先级,更灵活
  • 指纹算法优化

    • 请求指纹改用 MD5(32字符),性能提升约 40%
    • 数据指纹保持 SHA256(64字符),确保数据准确性
    • 针对不同场景选择最优算法,兼顾性能与准确性
  • 模块优化

    • 删除未使用的 hook.py(钩子系统)
    • priority.pymiddleware 移至 utils(非中间件功能)
    • throttle.py 作为可选中间件,用户可手动启用
  • 日志格式优化

    • 修复 enabled filtersenabled downloader 日志异常换行
    • 统一组件启用信息的输出格式
  • 导入优化

    • safe_get_config 导入移至文件头部,消除重复导入
    • 优化 downloader/__init__.pymemory_filter.pyqueue_manager.py 等文件
  • 模板文件更新

    • 更新所有 6 个项目模板的配置示例
    • 添加优先级规则说明注释

v1.2.0

  • Redis Key 重构:引入 RedisKeyManager 统一管理 Redis Key 的生成和验证
    • 支持项目级别和爬虫级别的 Key 命名规范
    • 支持在同一个项目下区分不同的爬虫
    • 集成 RedisKeyValidator 确保 Key 命名规范一致性
    • 详细文档请参见 Redis Key 重构说明

如有问题或建议,欢迎提交 Issue

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

crawlo-1.6.1.tar.gz (587.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

crawlo-1.6.1-py3-none-any.whl (839.6 kB view details)

Uploaded Python 3

File details

Details for the file crawlo-1.6.1.tar.gz.

File metadata

  • Download URL: crawlo-1.6.1.tar.gz
  • Upload date:
  • Size: 587.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for crawlo-1.6.1.tar.gz
Algorithm Hash digest
SHA256 2c0def76f637cb0e5a81b37d037993c710d0de06a707c6a04fcd27c07e4cf718
MD5 066171290f3b246afba86f96600958f4
BLAKE2b-256 54a14a218509b3f28a2fbf86c7607f3cc25018b0a275ba71a752e425dec6e00b

See more details on using hashes here.

File details

Details for the file crawlo-1.6.1-py3-none-any.whl.

File metadata

  • Download URL: crawlo-1.6.1-py3-none-any.whl
  • Upload date:
  • Size: 839.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for crawlo-1.6.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a9e78fa2c686e54358d127f86db4256fa4f256fcbc11a3c4f0d1c147c849f177
MD5 47eea0dd784acd4fe1afe7de2da6f651
BLAKE2b-256 6d2219dafc28e378e5c2244ed5d8f494117e4677a3e3fe93b485c52fce8b6b6f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page