基于scrapy-redis的分布式爬虫
一、介绍
1、原生的scrapy框架
原生的scrapy框架是实现不了分布式的,其原因有:
1. 因为多台机器上部署的scrapy会各自拥有各自的调度器,这样就使得多台机器无法分配start_urls列表中的url。(多台机器无法共享同一个调度器)
2. 多台机器爬取到的数据无法通过同一个管道对数据进行统一的数据持久出存储。(多台机器无法共享同一个管道)
2、基于scrapy-redis组件的分布式爬虫
1. scrapy-redis组件中为我们封装好了可以被多台机器共享的调度器和管道,我们可以直接使用并实现分布式数据爬取。 2. 实现方式 基于该组件的RedisSpider类 基于该组件的RedisCrawlSpider类 3. 配置 1,下载scrapy-redis组件:pip install scrapy-redis 2,redis配置文件的配置 - 注释该行:bind 127.0.0.1,表示可以让其他ip访问redis - 将yes该为no:protected-mode no,表示可以让其他ip操作redis
二、搭建分布式爬虫
1、搭建分布式的流程
1.下载scrapy-redis组件:pip install scrapy-redis 2.创建scrapy工程和爬虫文件(可以创建基于原生的分布式,可以创建基于CrawlSpider的分布式) scrapy startproject projectName scrapy genspider -t crawl spiderName www.xxx.com 3.修改爬虫文件中的代码: 3.1 导包:from scrapy_redis.spiders import RedisCrawlSpider 3.2 将爬虫类的父类修改成基于RedisSpider或者RedisCrawlSpider 注意:如果原始爬虫文件是基于Spider的,则应该将父类修改成RedisSpider 如果原始爬虫文件是基于CrawlSpider的,则应该将其父类修改成RedisCrawlSpider 3.3 allowed_domains 和 start_urls删除 3.4 增加一个新的属性:redis_key = xxx 这个属性值xxx就是scrpy-redis组件中调度器队列的名称 4.修改配置文件settings.py 4.0 scrapy_redis是scrapy-redis组件中提供的一个类 4.1 开启使用scrapy-redis组件中封装好的调度器(可以被共享的调度器) # 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用scrapy-redis组件自己的调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据 SCHEDULER_PERSIST = True # 是否允许暂停 4.2 指定可以被共享的管道: ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400 } 5. 指定持久化存储时,数据存储的数据库的相关信息: REDIS_HOST = 'redis服务的ip地址' REDIS_PORT = 6379 REDIS_ENCODING = 'utf-8' REDIS_PARAMS = {'password':'123'} # 不设密码可不写这行 6.配置redis数据库:redis.windows.conf protected-mode no #bind 127.0.0.1 7.开启redis的server and client (windows下开启) redis-server.exe redis.windows.conf redis-cli 8.运行当前的爬虫文件 scrapy runspider spiderName.py 注意此时不是:scrapy crawl spiderName 9.处理起始url: 在redis-cli中执行:lpush redis_key属性的值 起始url
2、代码实现
爬取抽屉网站的所有页码的链接标题和提交方 1. settings.py USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36' ROBOTSTXT_OBEY = False # 增加了一个去重容器类的配置, 作用使用Redis的set集合来存储请求的指纹数据, 从而实现请求去重的持久化 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用scrapy-redis组件自己的调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 配置调度器是否要持久化, 也就是当爬虫结束了, 要不要清空Redis中请求队列和去重指纹的set。如果是True, 就表示要持久化存储, 就不清空数据, 否则清空数据 SCHEDULER_PERSIST = True ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400 } REDIS_HOST = '192.168.3.16' REDIS_PORT = 6379 2. 爬虫文件 # -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from scrapy_redis.spiders import RedisCrawlSpider from chouti_redis.items import ChoutiRedisItem class ChoutiSpider(RedisCrawlSpider): name = 'chouti' # allowed_domains = ['https://dig.chouti.com/'] # start_urls = ['https://dig.chouti.com/'] # scrapy-redis组件中提供的调度器队列的名称 redis_key = 'ct' link = LinkExtractor(allow=r'/all/hot/recent/\d+') rules = ( # 规则解析器 # follow = True:将链接提取器继续作用到链接提取器提取出的链接所对应的页面中 Rule(link, callback='parse_item', follow=True), ) def parse_item(self, response): div_list = response.xpath('//div[@id="content-list"]/div') for div in div_list: title = div.xpath('./div[4]/div[1]/a[1]/text()').extract_first() submitted = div.xpath('./div[4]/div[2]/a[4]/b/text()').extract_first() item = ChoutiRedisItem() item['title'] = title item['submitted'] = submitted yield item 3. items.py class ChoutiRedisItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() title = scrapy.Field() submitted = scrapy.Field() 4. 开启分布式爬虫 1,在多台机器上开启爬虫程序 scrapy runspider spiderName.py 2,在主机器上开启redis # 开启服务端 redis-server.exe redis.windows.conf # 开启客户端 redis-cli # 在redis客户端中设置起始url lpush ct https://dig.chouti.com/ # 爬取到数据后,在redis中会生成下面几个key "chouti:items" "chouti:requests" "chouti:dupefilter"