安装
pip3 install scrapy-redis
使用scrapy_redis好处
reqeust去重,爬虫持久化,和轻松实现分布式
提供了下面四种组件
- Scheduler
- Duplication Filter
- Item Pipeline
- Base Spider
工作流程
获取 scrapy-redis 源码文件
git clone https://github.com/rolando/scrapy-redis.git
scrapy-redis 源码中有自带一个example-project项目,这个项目包含3个spider,分别是dmoz, myspider_redis,mycrawler_redis。
dmoz (class DmozSpider(CrawlSpider))
执行方式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 = ['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地址。
执行方式scrapy runspider myspider_redis.py
或scrapy crawl myspider_redis
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,能够支持分布式的抓取。因为采用的是crawlSpider,所以需要遵守Rule规则,以及callback不能写parse()方法。
- 同样也不再有start_urls了,取而代之的是redis_key,scrapy-redis将key从Redis里pop出来,成为请求的url地址
执行方式scrapy runspider myspider_redis.py
或scrapy crawl myspider_redis
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,
}
settings设置
-
使用scrapy_redis自己的去重组件,不再使用scrapy框架内部的去重组件
“DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"`
-
使用scrapy_redis自定义的调度器组件,不再使用scrapy框架自带的调度器组件
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
-
允许暂停,redis数据库中的保存的任务不会被清空,可以恢复和暂停(断点爬取)
SCHEDULER_PERSIST = True
-
如果不使用默认的request队列模式(则设置队列模式)
# 调度器存储request队列的模式(三种)
#SpiderPriorityQueue:是scrapy_redis框架(默认)的请求队列形式
#(有自己的优先级),按照redis数据库中的有序集合的方式取
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderPriorityQueue"
#SpiderQueu:请求队列形式,按照先进先出的方式
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderQueue"
#SpiderStack:请求队列形式,按照先进的后出的方式(类似栈的结构)
#SCHEDULER_QUEUE_CLASS = "scrapy_redis.queue.SpiderStack"`
-
如果需要将item数据统一存放在redis数据库中(可选)
'scrapy_redis.pipelines.RedisPipeline'
item数据全部存储在redis 数据库中,现在要把数据全部取出来放在mysql或者mongodb数据库中,步骤:
1.创建redis数据库连接(mysql或者mongodb数据库连接)
2.取数据 (list 使用lpop或者rpop取数据)
3.将数据存储mysql或者mongodb 数据库中
4.相关命令:http://www.redis.cn/commands.html#list -
redis数据库配置
#指定要存储数据的redis数据库的hsot(ip)
REDIS_HOST = '118.24.255.219'
#指定要存储数据的redis数据库的端口号
# mysql(3306) mongodb(27017) redis(6379)
REDIS_PORT = 6379
爬虫文件设置
-
如果要使用scrapy_redis的去重和存储功能(没有实现分布式),则只需要修改settings.py设置文件,爬虫部分代码照常
-
实现crawlSpider的分布式爬虫
step1:导入RedisCrawlSpiderfrom scrapy_redis.spiders import RedisCrawlSpider
step2:修改爬虫文件继承的类
class MyCrawler(RedisCrawlSpider)
step3:添加redis_key(根据redis_key从redis数据库中获取起始任务)
redis_key = '爬虫名称:start_urls' 注意:需要将原来的start_urls去重
其他代码照常不变
-
实现scrapy.spider的分布式爬虫
step1:导入RedisSpiderfrom scrapy_redis.spiders import RedisSpider
step2:修改爬虫文件继承的类
class MySpider(RedisSpider):
step3:添加redis_key(根据redis_key从redis数据库中获取起始任务)
redis_key = '爬虫名称:start_urls' 注意:需要将原来的start_urls去重
其他代码照常不变
redis数据库
数据类型
string、hash、list、set、zset
优势
非关系型数据库,redis数据库是基于内存的存储,读写的效率高。
master端与slave端
master端(主节点):
主要是保存Requst请求,指纹,items数据,设置起始任务
(一般master不负责爬取工作)
slave端(从节点):
爬虫端,从master端获取任务,请求获取响应结果,
提取数据,获取新的url任务,将获取的数据和新的请求,
交给 master 端管理