​Python分布式爬虫完全教程:从基础原理到Scrapy-Redis实战(附完整源码)​

​1. 为什么需要分布式爬虫?​

作为爬虫工程师,我们经常面临这样的挑战:

  • ​单机爬虫的瓶颈​​:当需要爬取百万级页面时,单台机器的CPU、内存和网络带宽成为限制
  • ​反爬机制​​:目标网站可能对单一IP的频繁请求进行封禁
  • ​效率需求​​:希望爬虫能够24小时不间断工作,充分利用多台机器的资源

​分布式爬虫解决方案​​:


​2. 分布式爬虫核心原理​

​(1) 基本架构​

[主节点] (任务调度)
  │
  ├──[爬虫节点1] → 爬取URL1 → 存储数据
  ├──[爬虫节点2] → 爬取URL2 → 存储数据
  └──[爬虫节点N] → 爬取URLN → 存储数据

​关键组件​​:

  • ​任务队列​​:存储待爬取的URL(Redis/MQ)
  • ​去重集合​​:记录已爬URL避免重复(Redis Set/Bloom Filter)
  • ​结果存储​​:MongoDB/MySQL存储爬取数据

​(2) 分布式核心技术点​

# 伪代码展示核心逻辑
while True:
    # 1. 从分布式队列获取任务
    url = redis.lpop('task_queue')  
    
    # 2. 检查是否已爬取(去重)
    if not redis.sismember('visited_urls', url):
        # 3. 执行爬取
        html = download(url)
        data = parse(html)
        
        # 4. 存储结果
        mongo.insert(data)
        redis.sadd('visited_urls', url)  # 标记已爬

​3. 实战:Scrapy-Redis分布式爬虫​

​(1) 环境准备​

pip install scrapy scrapy-redis redis pymongo

​(2) 项目结构​

distributed_spider/
├── spiders/
│   └── example_spider.py  # 爬虫核心逻辑
├── settings.py           # 分布式配置
└── requirements.txt

​(3) 核心配置(settings.py)​

# 启用Scrapy-Redis调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

# 确保所有爬虫共享相同的去重过滤
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"

# Redis连接配置
REDIS_HOST = 'your_redis_server'  # 可以是云Redis或本地
REDIS_PORT = 6379
REDIS_PASSWORD = 'your_password'  # 如果有密码

# 保持爬取状态(可选)
SCHEDULER_PERSIST = True

​(4) 爬虫实现(example_spider.py)​

import scrapy
from scrapy_redis.spiders import RedisSpider

class ExampleSpider(RedisSpider):
    name = 'example'
    # 注意:这里不定义start_urls,而是从Redis获取
    redis_key = 'example:start_urls'  # Redis中的起始URL键名

    def parse(self, response):
        # 示例:提取页面标题和链接
        yield {
            'url': response.url,
            'title': response.css('title::text').get(),
            'content_length': len(response.text)
        }
        
        # 提取新链接并加入队列(分布式自动处理)
        for link in response.css('a::attr(href)').getall():
            yield response.follow(link, callback=self.parse)

​4. 分布式部署实战​

​(1) 启动Redis服务​

# 本地启动(测试用)
redis-server

# 或使用云Redis(如阿里云Redis)

​(2) 添加初始任务​

import redis

r = redis.Redis(host='localhost', port=6379)
r.lpush('example:start_urls', 'https://example.com')  # 添加种子URL

​(3) 启动多个爬虫节点​

# 在多台机器/终端执行(相同代码)
scrapy crawl example

​关键说明​​:

  • 所有节点共享同一个Redis任务队列
  • 每个URL只会被一个节点爬取(自动去重)
  • 爬取结果可以统一存储到MongoDB

​5. 进阶优化技巧​

​(1) 动态负载均衡​

# 在settings.py中调整并发参数
CONCURRENT_REQUESTS = 32  # 每个节点并发数
DOWNLOAD_DELAY = 0.5      # 下载延迟(秒)

# 按域名限制并发
AUTOTHROTTLE_ENABLED = True

​(2) 断点续爬​

# SCHEDULER_PERSIST = True  # 已在配置中启用
# 重启爬虫时会自动继续未完成的任务

​(3) 结果存储优化(MongoDB示例)​

# pipelines.py
import pymongo

class MongoPipeline:
    def __init__(self, mongo_uri):
        self.mongo_uri = mongo_uri

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI')
        )

    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client['crawler_db']

    def process_item(self, item, spider):
        self.db['pages'].insert_one(dict(item))
        return item

​6. 完整项目源码结构​

distributed_spider/
├── scrapy.cfg
├── distributed_spider/
│   ├── __init__.py
│   ├── items.py          # 数据结构定义
│   ├── middlewares.py    # 中间件配置
│   ├── pipelines.py      # 数据存储管道
│   ├── settings.py       # 核心配置
│   └── spiders/
│       ├── __init__.py
│       └── example_spider.py  # 主爬虫逻辑
└── requirements.txt

​requirements.txt内容​​:

scrapy==2.11.0
scrapy-redis==0.7.2
redis==4.5.5
pymongo==4.3.3

​7. 常见问题解决方案​

​(1) 反爬应对策略​

# 在middlewares.py中添加
class RandomUserAgentMiddleware:
    def process_request(self, request, spider):
        request.headers['User-Agent'] = random.choice(USER_AGENTS)

​(2) 分布式监控​

# 使用Redis CLI监控任务队列
redis-cli llen example:start_urls  # 查看剩余任务数
redis-cli scard example:dupefilter # 查看过滤的URL数

​(3) 性能调优建议​

  1. 根据目标网站响应速度调整DOWNLOAD_DELAY
  2. 对重要域名设置单独的并发限制
  3. 使用Redis集群提高任务队列可靠性

​8. 总结:分布式爬虫开发要点​

核心要素实现方案注意事项
​任务分发​Redis队列确保所有节点连接同一Redis
​去重控制​Redis Set/Bloom Filter大规模爬取考虑Bloom Filter
​容错处理​持久化调度状态SCHEDULER_PERSIST=True
​扩展性​动态添加爬虫节点无状态设计,随时扩容

​下一步学习建议​​:

  1. 尝试结合​​Selenium​​处理JavaScript渲染页面
  2. 研究​​Kafka​​替代Redis作为任务队列
  3. 学习​​Docker​​部署分布式爬虫集群

通过这套方案,你可以轻松构建一个​​每小时处理数万页面​​的分布式爬虫系统!

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]