6 scrapy框架之分布式操作
分布式爬虫
一.redis简单回顾
1.启动redis:
mac/linux: redis-server redis.conf
windows: redis-server.exe redis-windows.conf
2.对redis配置文件进行配置:
- 注释该行:bind 127.0.0.1,表示可以让其他ip访问redis
- 将yes该为no:protected-mode no,表示可以让其他ip操作redis
二.scrapy基于redis的数据持久化操作流程
1.安装scrapy-redis组件:
- pip install scrapy-redis
- scrapy-redis是基于scrapy框架开发出的一套组件,其作用就是可以让scrapy实现分布式爬虫。
2.编写爬虫文件:
- 同之前scrapy中基于Spider或者CrawlSpider的编写方式一致。
3.编写管道文件:
- 在scrapy-redis组件中已经帮助我们封装好了一个专门用于连接存储redis数据库的管道(RedisPipeline),因此我们直接使用即可,无需自己编写管道文件。
4.编写配置文件:
- 在settings.py中开启管道,且指定使用scrapy-redis中封装好的管道。
ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400 }
- 该管道默认会连接且将数据存储到本机的redis服务中,如果想要连接存储到其他redis服务中需要在settings.py中进行如下配置:
REDIS_HOST = 'redis服务的ip地址' REDIS_PORT = 6379 REDIS_ENCODING = ‘utf-8’ REDIS_PARAMS = {‘password’:’123456’}
三.redis分布式部署
1.scrapy框架是否可以自己实现分布式?
- 不可以。原因有二。
其一:因为多台机器上部署的scrapy会各自拥有各自的调度器,这样就使得多台机器无法分配start_urls列表中的url。(多台机器无法共享同一个调度器)
其二:多台机器爬取到的数据无法通过同一个管道对数据进行统一的数据持久出存储。(多台机器无法共享同一个管道)
2.redis实现分布式基本流程:
- 使用基于scrapy-redis组件中的爬虫文件。
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from movieproject.items import MovieprojectItem #导入scrapy-redis中的模块 from scrapy_redis.spiders import RedisCrawlSpider class NnSpider(RedisCrawlSpider): name = 'nn' allowed_domains = ['www.id97.com'] #redis_key表示调度器中的队列(将要爬取的页面数据对应的url都需要放置到调度器队列中) redis_key = 'nnspider:start_urls' # 根据规则提取所有的页码链接 page_link = LinkExtractor(allow=r'/movie/\?page=\d') detail_link = LinkExtractor(restrict_xpaths='//div[contains(@class,"col-xs-1-5")]/div/a') # detail_link = LinkExtractor(allow=r'/movie/\d+\.html$') # follow : 是否跟进 rules = ( # 所有的页码不用处理,跟进即可 Rule(page_link, follow=True), # 所有的详情页处理,不用跟进 Rule(detail_link, callback='parse_item', follow=False), ) def parse_item(self, response): # 创建一个item对象 item = MovieprojectItem() # 电影海报 item['post'] = response.xpath('//a[@class="movie-post"]/img/@src').extract_first() # 电影名字 item['name'] = response.xpath('//h1').xpath('string(.)').extract_first() yield item
from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from redisPro.items import RedisproItem from scrapy_redis.spiders import RedisCrawlSpider class QiubaiSpider(RedisCrawlSpider): name = 'qiubai' #allowed_domains = ['https://www.qiushibaike.com/pic/'] #start_urls = ['https://www.qiushibaike.com/pic/'] #调度器队列的名称 redis_key = 'qiubaispider' #表示跟start_urls含义是一样,redis数据库里面的值 link = LinkExtractor(allow=r'/pic/page/\d+') rules = ( Rule(link, callback='parse_item', follow=True), ) def parse_item(self, response): div_list = response.xpath('//div[@id="content-left"]/div') for div in div_list: img_url = "https:"+div.xpath('.//div[@class="thumb"]/a/img/@src').extract_first() item = RedisproItem() item['img_url'] = img_url yield item
- 使用scrapy-redis组件中封装好的调度器,将所有的url存储到该指定的调度器中,从而实现了多台机器的调度器共享。
# 使用scrapy-redis组件的去重队列 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用scrapy-redis组件自己的调度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 是否允许暂停 SCHEDULER_PERSIST = True
- 使用scrapy-redis组件中封装好的管道,将每台机器爬取到的数据存储通过该管道存储到redis数据库中,从而实现了多台机器的管道共享。
ITEM_PIPELINES = { 'scrapy_redis.pipelines.RedisPipeline': 400, }
- 执行:scrapy runspider xxx.py,然后向调度器队列中传入起始url:lpush nnspider:start_urls http://www.xxx.com/