1.我们为什么要用到分布式爬虫?
Scrapy_redis在scrapy的基础上实现了更多,更强大的功能,具体体现在:reqeust去重,爬虫持久化,和轻松实现分布式
安装命令:pip3 install scrapy-redis
2.scrapy-redis的四种组件
Scrapy-redis提供了下面四种组件(components):(四种组件意味着这四个模块都要做相应的修改)
1.Scheduler
2.Duplication Filter
3.Item Pipeline
4.Base Spider
执行流程图:------------------>>>>>
爬虫文件根据url构造requets请求,经过引擎给调度器,爬虫文件的任务存到redis数据库,
这时候redis数据库就相当于一个共享资源池,Scheduler调度器再从redis里取出来,
item Pipeline用来做数据持久化,现在要继承于Base Spider
redis数据库实现什么功能?(作用)
通过redis实现调度器的队列和指纹的集合,redis数据库拥有丰富的存储类型,速度快,性能极高,比如list,hash,set,zset,string,set集合类型特点是不允许重复,
怎样将爬虫改成分布式爬虫?
实现分布式爬虫我们需要在settings设置几种选项
1.DUPEFILTER_
这里表示启用scrapy-redis里的去重组件,不实用scrapy默认的去重
2.SCHEDULER = “scrapy_redis.scheduler.Scheduler” 使用了scrapy-redis里面的调度器组件,不使用scrapy默认的调度器
3,SCHEDULER_PERSIST = True 允许暂停,redis请求的记录不会丢失,不清除Redis队列,可以恢复和暂停,
4.修改请求的队列模式 scrapy-redis默认的请求队列形式(有自己的优先级顺序)
是按照redis的有序集合排序出队列的,此外还需要设置地址和端口号
REDIS_HOST = ‘redis的主机的ip’ 指定要存储的redis的主机的ip,默认存储在127.0.0.1 REDIS_PORT = ‘6379’ 定要存储的redis的主机的port,默认6379
除此之外的设置:
导入 from scrapy_redis.spiders import RedisCrawlSpider/RedisSpider,不在继承原来的spider
不在使用原来的start_urls
必须指定redis_key,即启动爬虫的命令,参考格式:redis_key = ‘myspider:start_urls’
scrapy-redis源码
我们clone到的 scrapy-redis 源码中有自带一个example-project项目,这个项目包含3个spider,分别是dmoz, myspider_redis,mycrawler_redis。
一、dmoz (class DmozSpider(CrawlSpider))
注意:这里只是用到Redis的去重和保存功能,并没有实现分布式
这个爬虫继承的是CrawlSpider,它是用来说明Redis的持续性,当我们第一次运行dmoz爬虫,然后Ctrl + C停掉之后,再运行dmoz爬虫,之前的爬取记录是保留在Redis里的。
分析起来,其实这就是一个 scrapy-redis 版 CrawlSpider 类,需要设置Rule规则,以及callback不能写parse()方法。
执行方式:
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
class DmozSpider(CrawlSpider):
"""Follow categories and extract links."""
name = 'dmoz'
allowed_domains = ['dmoz.org']
start_urls = ['http://www.dmoz.org/']
#定义了一个url的提取规则,将满足条件的交给callback函数处理
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(),
}
二、myspider_redis (class MySpider(RedisSpider))
这个爬虫继承了RedisSpider, 它能够支持分布式的抓取,采用的是basic spider,需要写parse函数。
其次就是不再有start_urls了,取而代之的是redis_key,scrapy-redis将key从Redis里pop出来,成为请求的url地址。
from scrapy_redis.spiders import RedisSpider
class MySpider(RedisSpider):
"""Spider that reads urls from redis queue (myspider:start_urls)."""
name = 'myspider_redis'
#手动设置允许爬取的域
allowed_domains = ['设置允许爬取的域']
# 注意redis-key的格式:
redis_key = 'myspider:start_urls'
# 可选:等效于allowd_domains(),__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(MySpider, self).__init__(*args, **kwargs)
def parse(self, response):
return {
'name': response.css('title::text').extract_first(),
'url': response.url,}
三、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'
allowed_domains = ['设置允许爬取的域']
redis_key = 'mycrawler:start_urls'
rules = (
# follow all links
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,
}
总结
1 如果只是用到Redis的去重和保存功能,就选第一种;
2 如果要写分布式,则根据情况,选择第二种、第三种;
3 通常情况下,会选择用第三种方式编写深度聚焦爬虫。