一.分布式爬虫简介
1.介绍:
分布式爬虫就是多台计算机上都安装爬虫程序,重点是联合采集。比如爬虫A,B,C分别在三台服务器上,需要一个状态管理器集中分配,去重这三个爬虫的url,状态管理器也是一个服务,需要部署在某一个服务器上。
2.优点:
(1)充分利用多机器的带宽加速爬取;
(2)充分利用多机器的ip加速爬取速度
3.分布式需要解决的问题:
(1)request队列集中处理
(2)去重集中处理
二.Redis的简单使用
1.Redis的数据类型:
1.1(String)字符串:
键值对应
1.2(Hash)哈希:
设置多个键值对每个 hash 可以存储 232 -1 键值对(40多亿)
1.3(List)列表:
左边添加,右边添加,左边取前四个数据
1.4(Set)集合:
添加一个字符串到set()集合,成功返回1,如果已经存在则返回0,最大的成员数为 232 - 1
1.5(zset)有序集合:
添加元素到集合,不同的是每个元素都会关联一个double类型的分数,通过分数排序。
2.常用命令:
可参考:http://www.runoob.com/redis/redis-sets.html
三.scrapy-redis搭建分布式爬虫
1.github源码地址:
https://github.com/rmax/scrapy-redis
2.将scrapy-redis项目clone下到本地,需要src下的scrapy-redis文件:
导入scrapy-redis并安装redis(pip install redis)设置:
1 #在redis中启用调度存储请求队列。 2 SCHEDULER = “ scrapy_redis.scheduler.Scheduler ” 3 4 #确保所有蜘蛛通过redis共享相同的重复过滤器。 5 DUPEFILTER_CLASS = “ scrapy_redis.dupefilter.RFPDupeFilter ” 6 7 #默认请求序列化程序是pickle,但它可以更改为 8 具有加载和转储功能的任何模块#。请注意, 9 # python版本 10 之间的pickle不兼容。#警告:在蟒蛇3.x中,串行器必须返回字符串键和支持 11 #字节的值。由于这个原因,json或msgpack模块 12 默认不会#工作。在python 2.x中没有这样的问题,您可以使用 13 # 'json'或'msgpack'作为序列化程序。 14 # SCHEDULER_SERIALIZER = “scrapy_redis.picklecompat” 15 16 #不要清理redis队列,允许暂停/恢复抓取。 17 # SCHEDULER_PERSIST =真 18 19 #使用优先级队列安排请求。(默认) 20 # SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue' 21 22 #替代队列。 23 # SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.FifoQueue' 24 # SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.LifoQueue' 25 26 #最大空闲时间,防止蜘蛛在分布式爬网时被关闭。 27 #这仅在队列类为SpiderQueue或SpiderStack时才有效, 28 #也可能在您的蜘蛛第一次启动时阻塞同一时间(因为队列为空)。 29 # SCHEDULER_IDLE_BEFORE_CLOSE = 10 30 31 #将已删除的项目存储在redis中进行后期处理。 32 ITEM_PIPELINES = { 33 ' scrapy_redis.pipelines.RedisPipeline ': 300 34 } 35 36 #项目管道序列化并存储此redis密钥中的项目。 37 # REDIS_ITEMS_KEY ='%(蜘蛛)S:项的 38 39 #项目序列化程序默认为ScrapyJSONEncoder。你可以使用任何 40 #导入的路径,一个可调用对象。 41 # REDIS_ITEMS_SERIALIZER = 'json.dumps' 42 43 #指定连接到Redis时使用的主机和端口(可选)。 44 # REDIS_HOST = '本地主机' 45 # REDIS_PORT = 6379 46 47 #指定用于连接的完整Redis URL(可选)。 48 #如果设置,则优先于REDIS_HOST和REDIS_PORT设置。 49 # REDIS_URL = 'redis的://用户:通过@主机名:9001' 50 51 #定制redis的客户参数(即:套接字超时等) 52 # REDIS_PARAMS = {} 53 #使用自定义redis的客户端类。 54 # REDIS_PARAMS [ 'redis_cls'] = 'myproject.RedisClient' 55 56 #如果为True,则使用redis'``SPOP``操作。您必须使用``SADD`` 57 #命令将URL添加到redis队列。如果你这可能是有用的 58 #要避免在开始的URL列表和重复的顺序 59 #处理无关紧要。 60 # REDIS_START_URLS_AS_SET =假 61 62 #默认启动网址RedisSpider和RedisCrawlSpider关键。 63 # REDIS_START_URLS_KEY = '%(名)S:start_urls' 64 65 #使用除utf-8之外的其他编码进行redis。 66 # REDIS_ENCODING = 'latin1的'
3.配置setting:
# SCHEDULER覆盖原有的,在redis中启用调度存储请求队列 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 确保所有spider通过redis共享相同的重复过滤器 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 配置以便后期插入数据库等操作 ITEM_PIPELINES = { "scrapy_redis.pipelines.RedisPipeline": 300, }
监听,取不到url不会退出,telnet一直监听
4.将网址推送到redis,运行lpush myspider:start_urls 起始url:
不设定redis_key,默认为spider:start_urls:
如:lpush jobbole:start_urls http://blog.jobbole.com/all-posts
5.scrapy-redis源码介绍:
5.1collection.py:
get_redis_from_settings():将所有配置放到dict:params中,用于实例化redis对象。
get_redis():实例化redis对象,from_url方法优先。
5.2defaults.py:
设定默认连接参数。
5.3dupefilter.py(去重类,和scrapy的dupefilter.py几乎一模一样):
clear(self):清除request_fingerprint记录
close(self,reason):结束爬虫爬取时,调用
from_crawler(cls,crawler):类方法,调用from_settings方法初始化
from_settings(cls,settings):类方法初始化,预留钩子
log(self,request,spider):根据传入的debug或者默认显示log
request_fingerprint(self,request):根据请求信息返回经过sha1计算后的值
request_seen(self,request)调用request_fingerprint,判断是否访问过
5.4picklecompat.py:
process_item():调用_process_item。
_process_item():通过rpush方法放到redis的列表里。
5.6queue.py:使用redis制作的队列,有Fifo(先进先出)、Lifo(后进先出)、PriorityQueue(有序集合取第一个)三种
5.7scheduler.py(调度器类):
enqueue_request():不是白名单且访问过的,往队列里放Request对象
next_request():从队列里取值
5.8spiders.py:爬虫类
5.9utils.py:
bytes_to_str():字节转成字符串,默认utf-8