安装scrapy-redis
pip install scrapy-redis -i https://pypi.douban.com/simple
Scrapy-Redis分布式策略
假设有四台电脑:Windows 10、Mac OS X、Ubuntu 16.04、CentOS 7.2,任意一台电脑都可以作
为 Master端 或 Slaver端,比如:
- `Master端`(核心服务器) :使用 Windows 10,搭建一个Redis数据库,不负责爬取,只负责url指
- 纹判重、Request的分配,以及数据的存储
- `Slaver端`(爬虫程序执行端) :使用 Mac OS X 、Ubuntu 16.04、CentOS 7.2,负责执行爬虫程
- 序,运行过程中提交新的Request给Master
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jw33HV2u-16024
25589171)(img/masterAndslaver.png)]
1. 首先Slaver端从Master端拿任务(Request、url)进行数据抓取,Slaver抓取数据的同时,产
2. 生新任务的Request便提交给 Master 处理;
3. Master端只有一个Redis数据库,负责将未处理的Request去重和任务分配,将处理后的Requ
4. est加入待爬队列,并且存储爬取的数据。
Scrapy-Redis默认使用的就是这种策略,我们实现起来很简单,因为任务调度等工作Scrapy-
Redis都已经帮我们做好了,我们只需要继承RedisSpider、指定redis_key就行了。
缺点是,Scrapy-Redis调度的任务是Request对象,里面信息量比较大(不仅包含url,还有ca
llback函数、headers等信息),可能导致的结果就是会降低爬虫速度、而且会占用Redis大量
的存储空间,所以如果要保证效率,那么就需要一定硬件水平。
安装Redis
准备两台电脑 都装redis
master端
可以保证master上面的redis可以被连接
注意:redis默认配置是不让远程连接,需要注释掉redis.conf配置文件中
的 #bind 127.0.0.1 #protected-mode no
启动master端的redis数据库
redis--cli --启动本地数据库
ping --检测数据库连接状态,返回PONG,则表示成功
set key1 'hello' -- 存入{'key1':'hello'}
slave端
redis-cli -h 192.168.199.108,-h 参数表示连接到指定主机的redis数据库地址 -p 可以指定端口
--keys 查询刚才存入的键数据
-- get key1 查询刚才存入的key1的值
如果查询到刚才在master端存入的数据则表示配置成功
注意:Slave端无需启动redis-server,Master端启动即可。只要 Slave 端读取到了 Master 端的
Redis 数据库,则表示能够连接成功,可以实施分布式。
分布式爬虫源码
链接:https://pan.baidu.com/s/16aXPHtePiarEIFATwcILbw 提取码:hhhh
源码详解
一、dmoz (class DmozSpider(CrawlSpider))
这个爬虫继承的是CrawlSpider,它是用来说明Redis的持续性,当我们第一次运行dmoz爬
虫,然后Ctrl + C停掉之后,再运行dmoz爬虫,之前的爬取记录是保留在Redis里的。
分析起来,其实这就是一个 scrapy-redis 版 CrawlSpider 类,需要设置Rule规则,以及callback
不能写parse()方法。
执行方式:scrapy crawl dmoz
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class DmozSpider(CrawlSpider):
"""Follow categories and extract links."""
name = 'dmoz'
allowed_domains = ['dmoztools.net/']
start_urls = ['http://dmoztools.net/']
rules = [
Rule(LinkExtractor(
restrict_css=('.top-cat', '.sub-cat', '.cat-item')
), callback='parse_directory', follow=True),
]
def parse_directory(self, response):
for div in response.css('.title-and-desc'):
yield {
'name': div.css('.site-title::text').extract_first(),
'description': div.css('.site-descr::text').extract_first().strip(),
'link': div.css('a::attr(href)').extract_first(),
}
二、mycrawler_redis (class MyCrawler(RedisCrawlSpider))
这个RedisCrawlSpider类爬虫继承了RedisCrawlSpider,能够支持分布式的抓取。因为采
用的是crawlSpider,所以需要遵守Rule规则,以及callback不能写parse()方法。
同样也不再有start_urls了,取而代之的是redis_key,scrapy-redis将key从Redis里pop出
来,成为请求的url地址。
from scrapy.spiders import Rule
from scrapy.linkextractors import LinkExtractor
from scrapy_redis.spiders import RedisCrawlSpider
class MyCrawler(RedisCrawlSpider):
"""Spider that reads urls from redis queue (myspider:start_urls)."""
# 爬虫名
name = 'mycrawler_redis'
# redis_key: 类似start_url,但是只是redis的一个key
# 监听redis中的key
redis_key = 'mycrawler:start_urls'
# 允许的域名
allowed_domains = ['dmoz.org']
# 规则
rules = (
Rule(LinkExtractor(), callback='parse_page', follow=True),
)
# __init__方法必须按规定写,使用时只需要修改super()里的类名参数即可
def __init__(self, *args, **kwargs):
# Dynamically define the allowed domains list.
domain = kwargs.pop('domain', '')
self.allowed_domains = filter(None, domain.split(','))
# 修改这里的类名为当前类名
super(MyCrawler, self).__init__(*args, **kwargs)
def parse_page(self, response):
return {
'name': response.css('title::text').extract_first(),
'url': response.url,
}
注意:
同样的,RedisCrawlSpider类不需要写allowd_domains和start_urls:
scrapy-redis将从在构造方法__init__()里动态定义爬虫爬取域范围,也可以选择直接写allowd_domains。
必须指定redis_key,即启动爬虫的命令,参考格式:redis_key = 'myspider:start_urls'
根据指定的格式,start_urls将在 Master端的 redis-cli 里 lpush 到 Redis数据库里,RedisSpider 将在数据
库里获取start_urls。
执行方式:
通过runspider方法执行爬虫的py文件(也可以分次执行多条),爬虫(们)将处于等待准备状态:
scrapy runspider mycrawler_redis.py
在Master端的redis-cli输入push指令,参考格式:
$redis > lpush mycrawler:start_urls http://www.dmoz.org/
爬虫获取url,开始执行。
三、myspider_redis (class MySpider(RedisSpider))
这个爬虫继承了RedisSpider, 它能够支持分布式的抓取,采用的是basic spider,需要
写parse函数。
其次就是不再有start_urls了,取而代之的是redis_key,scrapy-redis将key从Redis里po
p出来,成为请求的url地址。
from scrapy_redis.spiders import RedisSpider
class MySpider(RedisSpider):
"""Spider that reads urls from redis queue (myspider:start_urls)."""
# 爬虫名
name = 'myspider_redis'
# redis_key: 类似start_url,但是只是redis的一个key
# 监听当前爬虫所连接的redis数据库中的指定key为‘myspider:start_urls’是否改变
redis_key = 'myspider:start_urls'
# 允许的域名
allowed_domains = ['dmoz.org']
def parse(self, response):
pass
注意:
RedisSpider类 不需要写allowd_domains和start_urls:
scrapy-redis将从在构造方法__init__()里动态定义爬虫爬取域范围,也可以选择直接
写allowd_domains。
必须指定redis_key,即启动爬虫的命令,参考格式:redis_key = 'myspider:start_urls'
根据指定的格式,start_urls将在 Master端的 redis-cli 里 lpush 到 Redis数据库里,RedisS
pider 将在数据库里获取start_urls。
执行方式:
通过runspider方法执行爬虫的py文件(也可以分次执行多条),爬虫(们)将处于等待准备状态:
scrapy runspider myspider_redis.py
在Master端的redis-cli输入push指令,参考格式:
$redis > lpush myspider:start_urls http://dmoztools.net/
Slaver端爬虫获取到请求,开始爬取。
总结:
如果只是用到Redis的去重和保存功能,就选第一种;
如果要写分布式,则根据情况,选择第二种、第三种;
通常情况下,会选择用第二种方式编写深度聚焦爬虫