一、scrapy框架不能自己實現分布式爬蟲的原因
其一:因為多台機器上部署的scrapy會各自擁有各自的調度器,這樣就使得多台機器無法分配start_urls列表中的url。(多台機器無法共享同一個調度器)
其二:多台機器爬取到的數據無法通過同一個管道對數據進行統一的數據持久出存儲。(多台機器無法共享同一個管道)
二、基於scrapy-redis組件作用
其一:給原生的scrapy提供了可以被共享的調度器和管道
其二:分布爬取的數據必須存儲到redis中
三、scrapy-redis安裝
# 安裝scrapy-redis分布式爬蟲組件 pip install scrapy-redis
四、基於scrapy-redis組件的分布式爬蟲
scrapy-redis組件中為我們封裝好了可以被多台機器共享的調度器和管道,我們可以直接使用並實現分布式數據爬取。
將爬蟲類的父類修改成基於RedisSpider或者RedisCrawlSpider。
注意:如果原始爬蟲文件是基於Spider的,則應該將父類修改成RedisSpider,如果原始爬蟲文件是基於CrawlSpider的,則應該將其父類修改成RedisCrawlSpider。
- 注釋或者刪除start_urls列表,切加入redis_key屬性,屬性值為scrpy-redis組件中調度器隊列的名稱
實現方式:
1.基於該組件的RedisSpider類配置:爬蟲文件
# -*- coding: utf-8 -*- import scrapy from ..items import WangyiproItem from selenium import webdriver # 配置scrapy-redis分布式 # 給原生的scrapy提供了可以被共享的調度器和管道 from scrapy_redis.spiders import RedisSpider # 繼承分布式爬蟲類(RedisSpider) class WangyiSpider(RedisSpider): name = 'wangyi' # allowed_domains = ['www.xx.com'] # 在分布式爬蟲中,不再需要指定起始url # start_urls = ['http://www.xx.com/'] # 指定被共享的調度器隊列的名稱 redis_key = "sunQueue" # 數據解析 def parse(self, response): pass
2.基於該組件的RedisCrawlSpider類配置:爬蟲文件
# -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from fbssunPro.items import FbssunproItem # 配置scrapy-redis分布式 # 給原生的scrapy提供了可以被共享的調度器和管道 from scrapy_redis.spiders import RedisCrawlSpider # 繼承分布式爬蟲類(RedisCrawlSpider) class SunSpider(RedisCrawlSpider): name = 'sun' # allowed_domains = ['www.xx.com'] # 在分布式爬蟲中,不再需要指定起始url # start_urls = ['http://www.xx.com/'] # 指定被共享的調度器隊列的名稱 redis_key = "sunQueue" # 規則解析器 rules = ( Rule(LinkExtractor(allow=r'正則表達式'), callback='parse_item', follow=True), ) # 數據解析 def parse_item(self, response): pass
3.爬蟲配置文件settings.py
#在配置文件中進行相關配置,開啟使用scrapy-redis組件中封裝好的調度器 # 使用scrapy-redis組件的去重隊列 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" # 使用scrapy-redis組件自己的調度器 SCHEDULER = "scrapy_redis.scheduler.Scheduler" # 是否允許暫停 SCHEDULER_PERSIST = True #在配置文件中進行爬蟲程序鏈接redis的配置: REDIS_HOST = 'redis服務的ip地址' REDIS_PORT = 6379 REDIS_ENCODING = ‘utf-8’ REDIS_PARAMS = {‘password’:’123456’}
五、基於scrapy-redis組件的redis數據庫配置
注意:scrapy-redis爬蟲組件是基於redis數據庫做數據持久化,不能是別的數據庫
修改redis啟動配置文件:redis.windows.conf
# redis.windows.conf配置: - 注釋該行:bind 127.0.0.1,表示可以讓其他ip訪問redis - 將yes該為no:protected-mode no,表示可以讓其他ip操作redis ———————————————數據庫操作———————----—————— # 啟動redis數據庫服務端(當前文件下啟動) redis-server ./redis.windows.conf # 啟動redis客戶端 redis-cli # 向數據中添加調度器 隊列名稱 # 調度器的隊列名稱就是redis_key值 # 爬蟲文件定義的redis_key = "sunQueue" # 自定義隊列名 lpush sunQueue www.xxx.com # 添加爬蟲起始url
五、基於scrapy-redis分布式爬蟲啟動步驟
# 開啟redis數據庫 開啟redis服務器:redis-server 配置文件 開啟redis客戶端:redis-cli # 運行爬蟲文件,監聽起始請求對象 進入爬蟲文件目錄:cd ./spiders 運行爬蟲文件:scrapy runspider SpiderFile # 調度器隊列中等待請求對象 向調度器隊列中扔入一個起始url(在redis客戶端中操作):lpush redis_key屬性值 起始url
六、基於scrapy-redis分布式爬蟲實例(東莞陽光網)
需求:通過分布式爬蟲(scrapy-redis)獲取網站文章標題信息,url:http://wz.sun0769.com/index.php/question/questionType?type=4&page=
爬蟲文件:sun.py
# -*- coding: utf-8 -*- import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from fbssunPro.items import FbssunproItem # 配置scrapy-redis分布式 # 給原生的scrapy提供了可以被共享的調度器和管道 from scrapy_redis.spiders import RedisCrawlSpider # 繼承分布式爬蟲類(RedisCrawlSpider) class SunSpider(RedisCrawlSpider): name = 'sun' # allowed_domains = ['www.xx.com'] # 在分布式爬蟲中,不再需要指定起始url # start_urls = ['http://www.xx.com/'] # 指定被共享的調度器隊列的名稱 redis_key = "sunQueue" # 規則解析器 rules = ( Rule(LinkExtractor(allow=r'type=4&page=\d+'), callback='parse_item', follow=True), ) # 數據解析 def parse_item(self, response): tr_list = response.xpath('//*[@id="morelist"]/div/table[2]//tr/td/table//tr') for tr in tr_list: # 獲取所有的文章標題 title = tr.xpath('./td[2]/a[2]/text()').extract_first() item = FbssunproItem() item['title'] = title # 提交數據到管道 yield item
Item對象類文件:items.py
import scrapy class FbssunproItem(scrapy.Item): # define the fields for your item here like: title = scrapy.Field()
管道文件類文件:pipelines.py
class FbssunproPipeline(object): # 持久化存儲 def process_item(self, item, spider): # item對象結果是一個字典 print(item) return item
爬蟲配置文件:settings.py
BOT_NAME = 'fbssunPro' SPIDER_MODULES = ['fbssunPro.spiders'] NEWSPIDER_MODULE = 'fbssunPro.spiders' # Obey robots.txt rules ROBOTSTXT_OBEY = True # 開啟管道 ITEM_PIPELINES = { 'fbssunPro.pipelines.FbssunproPipeline': 300, } # 配置調度器 DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter" SCHEDULER = "scrapy_redis.scheduler.Scheduler" SCHEDULER_PERSIST = True # 指定數據庫 REDIS_HOST = '192.168.1.102' REDIS_PORT = 6379
完成!!!