基於scrapy-redis兩種形式的分布式爬蟲
redis分布式部署
1.scrapy框架是否可以自己實現分布式?
- 不可以。原因有二。
其一:因為多臺機器上部署的scrapy會各自擁有各自的調度器,這樣就使得多臺機器無法分配start_urls列表中的url。(多臺機器無法共享同一個調度器)
其二:多臺機器爬取到的數據無法通過同一個管道對數據進行統一的數據持久出存儲。(多臺機器無法共享同一個管道)
2.基於scrapy-redis組件的分布式爬蟲
- scrapy-redis組件中為我們封裝好了可以被多臺機器共享的調度器和管道,我們可以直接使用並實現分布式數據爬取。
- 實現方式:
1.基於該組件的RedisSpider類
2.基於該組件的RedisCrawlSpider類
3.分布式實現流程:上述兩種不同方式的分布式實現流程是統一的
- 3.1 下載scrapy-redis組件:pip install scrapy-redis
- 3.2 redis配置文件的配置:
- 註釋該行:bind 127.0.0.1,表示可以讓其他ip訪問redis
- 將yes該為no:protected-mode no,表示可以讓其他ip操作redis
3.3 修改爬蟲文件中的相關代碼:
- 將爬蟲類的父類修改成基於RedisSpider或者RedisCrawlSpider。註意:如果原始爬蟲文件是基於Spider的,則應該將父類修改成RedisSpider,如果原始爬蟲文件是基於CrawlSpider的,則應該將其父類修改成RedisCrawlSpider。
- 註釋或者刪除start_urls列表,切加入redis_key屬性,屬性值為scrpy-redis組件中調度器隊列的名稱
3.4 在配置文件中進行相關配置,開啟使用scrapy-redis組件中封裝好的管道
ITEM_PIPELINES = { ‘scrapy_redis.pipelines.RedisPipeline‘: 400 }
3.5 在配置文件中進行相關配置,開啟使用scrapy-redis組件中封裝好的調度器
# 使用scrapy-redis組件的去重隊列
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# 使用scrapy-redis組件自己的調度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 是否允許暫停
SCHEDULER_PERSIST = True
3.6 在配置文件中進行爬蟲程序鏈接redis的配置:
REDIS_HOST = ‘redis服務的ip地址‘
REDIS_PORT = 6379
REDIS_ENCODING = ‘utf-8’
REDIS_PARAMS = {‘password’:’123456’}
3.7 開啟redis服務器:redis-server 配置文件
3.8 開啟redis客戶端:redis-cli
3.9 運行爬蟲文件:scrapy runspider SpiderFile
3.10 向調度器隊列中扔入一個起始url(在redis客戶端中操作):lpush redis_key屬性值 起始url
1.基於該組件的RedisSpider類爬蟲代碼如下
數據:國產器械,數據條數10萬條
1 # -*- coding: utf-8 -*- 2 import scrapy 3 from scrapy_redis.spiders import RedisSpider 4 from redisSpiderPro.items import RedisspiderproItem 5 class RedisspidertestSpider(RedisSpider): 6 name = ‘redisSpiderTest‘ 7 # allowed_domains = [‘www.xxx.com‘] 8 # start_urls = [‘http://www.xxx.com/‘] 9 10 #調度器隊列的名稱 11 redis_key=‘data‘ 12 url=‘http://db.pharmcube.com/database/cfda/detail/cfda_cn_instrument/‘ 13 pageNum=1 14 def parse(self, response): 15 num=response.xpath(‘/html/body/div/table/tbody/tr[1]/td[2]/text()‘).extract_first() 16 name=response.xpath(‘/html/body/div/table/tbody/tr[2]/td[2]/text()‘).extract_first() 17 18 item=RedisspiderproItem() 19 item[‘num‘]=num 20 item[‘name‘]=name 21 yield item 22 23 if self.pageNum<=10000: 24 self.pageNum+=1 25 new_url=self.url+str(self.pageNum) 26 yield scrapy.Request(url=new_url,callback=self.parse)爬蟲代碼
setting配置
1 USER_AGENT = ‘Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36‘ 2 3 ROBOTSTXT_OBEY = False 4 5 #管道 6 ITEM_PIPELINES = { 7 ‘scrapy_redis.pipelines.RedisPipeline‘: 400 8 } 9 10 # 使用scrapy-redis組件的去重隊列 11 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" 12 # 使用scrapy-redis組件自己的調度器 13 SCHEDULER = "scrapy_redis.scheduler.Scheduler" 14 # 是否允許暫停 15 SCHEDULER_PERSIST = True 16 17 18 #redis連接數據庫的參數 19 REDIS_HOST = ‘192.168.19.38‘ 20 REDIS_PORT = 6379 21 #編碼格式 22 # REDIS_ENCODING = ‘utf-8’ 23 #用戶名密碼 24 # REDIS_PARAMS = {‘password’:’123456’}setting
2.基於該組件的RedisCrawlSpider類爬蟲代碼如下
數據 抽屜網:爬取段子
爬蟲代碼:
1 import scrapy 2 from scrapy.linkextractors import LinkExtractor 3 from scrapy.spiders import CrawlSpider, Rule 4 from redisCrawlSpiderPro.items import RediscrawlspiderproItem 5 from scrapy_redis.spiders import RedisCrawlSpider 6 7 class CrawlspiderSpider(RedisCrawlSpider): 8 name = ‘CrawlSpider‘ 9 # allowed_domains = [‘www.xxx.com‘] 10 # start_urls = [‘http://www.xxx.com/‘] 11 12 redis_key=‘data‘ 13 link=LinkExtractor(allow=r‘/r/scoff/hot/\d+‘) 14 rules = ( 15 Rule(link, callback=‘parse_item‘, follow=True), 16 ) 17 18 def parse_item(self, response): 19 div_list=response.xpath(‘//div[@id="content-list"]/div‘) 20 for div in div_list: 21 item=RediscrawlspiderproItem() 22 item[‘title‘] = div.xpath(‘./div[3]/div/a/text()‘).extract_first() 23 item[‘author‘] = div.xpath(‘./div[3]/div[2]/a[4]/b/text()‘).extract_first() 24 yield item爬蟲代碼
基於scrapy-redis兩種形式的分布式爬蟲