文章目录
-
- 一、分布式爬虫基础概念
- 二、环境准备
-
- [1. 安装Redis](#1. 安装Redis)
- [2. Python依赖安装](#2. Python依赖安装)
- 三、实战:Scrapy-Redis分布式爬虫
-
- 步骤1:创建scrapy项目
- [步骤2:修改爬虫 `spiders/demo.py`](#步骤2:修改爬虫
spiders/demo.py) - 步骤3:修改settings.py(核心配置)
- 四、运行分布式集群
- [五、轻量方案:原生Python + Redis分布式爬虫(可集成Selenium)](#五、轻量方案:原生Python + Redis分布式爬虫(可集成Selenium))
一、分布式爬虫基础概念
单机爬虫局限:单机器带宽、IP、CPU有限,URL队列在内存,多开爬虫会重复抓取。
分布式架构(Master-Worker)
- Master(Redis服务):存放待爬URL队列、已爬URL去重集合、抓取结果。只做存储,不爬页面。
- Worker爬虫节点:多台服务器/多个进程,连接同一个Redis,从Redis取URL,请求网页、解析,新链接放回Redis队列。
所有Worker代码完全一样,直接复制到多台机器运行即可。
备选方案
- Scrapy-Redis:首选,上手快,成熟稳定,最主流
- 原生Python+Redis(requests/aiohttp):轻量,适合自定义逻辑(可以集成Selenium)
- Celery+Redis:任务分发,适合离散任务
二、环境准备
1. 安装Redis
- Windows:Redis Windows版本;Linux:
apt install redis-server - 启动redis:
redis-server,默认端口6379 - 开放远程访问(多机分布式需要):修改redis配置
bind 0.0.0.0,设置密码
2. Python依赖安装
bash
pip install scrapy scrapy-redis
三、实战:Scrapy-Redis分布式爬虫
步骤1:创建scrapy项目
bash
scrapy startproject dist_crawl
cd dist_crawl
scrapy genspider demo example.com
步骤2:修改爬虫 spiders/demo.py
python
from scrapy_redis.spiders import RedisSpider
class DemoSpider(RedisSpider):
name = "demo"
# Redis的key:从这个key读取起始url
redis_key = "demo:start_urls"
allowed_domains = ["example.com"]
def parse(self, response):
# 解析当前页面数据
yield {
"title": response.css("h1::text").get(),
"url": response.url
}
# 提取新链接,自动push到redis共享队列
for link in response.css("a::attr(href)").getall():
yield response.follow(link, callback=self.parse)
重点:继承
RedisSpider,不再写start_urls,起始URL由Redis推送。
步骤3:修改settings.py(核心配置)
python
# 开启scrapy-redis调度器:使用redis共享队列
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 全局去重过滤器(所有机器共用去重集合)
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 断点续爬:爬虫停止不清空redis队列,重启继续跑
SCHEDULER_PERSIST = True
# Redis连接地址(Master节点Redis)
REDIS_URL = "redis://127.0.0.1:6379/0"
# 如果redis有密码:redis://:mypassword@127.0.0.1:6379/0
# 管道:数据存入redis
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300,
}
# 常规爬虫配置
ROBOTSTXT_OBEY = False
CONCURRENT_REQUESTS = 16
DOWNLOAD_DELAY = 0.5
DEFAULT_REQUEST_HEADERS = {
"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"
}
四、运行分布式集群
- 启动Redis服务(Master机器)
- 所有Worker节点进入项目目录执行(多台机器都执行这条命令)
bash
scrapy crawl demo
此时爬虫会阻塞,等待Redis队列推送起始URL。
- 往Redis写入起始url(redis-cli执行)
redis
lpush demo:start_urls https://example.com
一旦推入URL,所有Worker会争抢消费任务,自动分布式抓取,URL不会重复。
Redis里存储的数据说明
demo:start_urls:待爬URL队列(list)demo:dupefilter:已爬URL指纹集合(set),全局去重demo:items:抓取完成的数据(list)
五、轻量方案:原生Python + Redis分布式爬虫(可集成Selenium)
如果你不想用Scrapy,想要requests/aiohttp,甚至把Selenium页面白屏巡检做成分布式任务,用这个模板。
bash
pip install redis requests
python
# distributed_worker.py
import redis
import requests
# Master Redis
r = redis.Redis(host="127.0.0.1", port=6379, db=0, decode_responses=True)
def get_task():
# 从队列左侧pop,阻塞式获取任务
return r.brpop("task_queue", timeout=5)
def save_result(data):
r.lpush("result_queue", str(data))
def is_url_crawled(url):
# 去重
return r.sismember("crawled_set", url)
def mark_crawled(url):
r.sadd("crawled_set", url)
def crawl(url):
resp = requests.get(url, timeout=10)
return {"url":url, "status":resp.status_code, "text":resp.text[:100]}
if __name__ == "__main__":
print("Worker节点启动,等待任务...")
while True:
task = get_task()
if not task:
continue
_, url = task
if is_url_crawled(url):
continue
try:
res = crawl(url)
save_result(res)
print(f"抓取成功:{url}")
except Exception as e:
print(f"抓取失败 {url}, err:{e}")
mark_crawled(url)
Master端推送任务(redis-cli)
redis
lpush task_queue https://example.com
多台机器同时运行这个脚本,就是分布式集群。你可以把
crawl()函数替换为之前Selenium页面白屏检测代码,实现分布式页面可用性巡检集群。