安装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的去重和保存功能,就选第一种;
如果要写分布式,则根据情况,选择第二种、第三种;
通常情况下,会选择用第二种方式编写深度聚焦爬虫