scrapy_redis
scrapy是一個通用的爬蟲架構,但是不支援分布式,scrapy_redis是為了更友善的實作scrapy分布式爬取,而提供了一些以redis為基礎的元件(僅有元件)。
scrapy_redis工作原理:
- 排程器将不再負責Url的排程,而是将url上傳給scrapy_redis元件,由元件負責組織、去重
- redis元件會通過指紋(key)來進行去重操作,并且把請求對象分發給不同的用戶端
- 用戶端拿到請求對象後,再交給引擎–下載下傳器
- pipeline不再負責本地化操作,而是把資料交給redis元件來負責寫入redis資料庫,達到資源共享、自動合并的目的
scrapy_redis組成:
Scheduler 排程器,scrapy本身不支援爬蟲分布,scrapy_redis的解決是把這個scrapy queue換成redis資料庫(也是指redis隊列),從同一個redis-server存放要爬取的request,便能讓多個spider去同一個資料庫裡讀取。
Duplication Filter 指紋過濾器,scrapy用集合實作這個request去重功能,scrapy中把已經發送的request指紋放到一個集合中,把下一個request的指紋放到集合中比對,如果該指紋存在于集合中,說明這個request發送過了,如果沒有則繼續操作。
Item Pipeline 管道,引擎将(spider傳回的)爬取到的item給Item Pipeline,scrapy_redis的Item Pipeline将爬取到的item存入redis的items pipeline。
Base Spider
分布式爬蟲例子(爬取讀書網的圖書名稱和封面圖檔連結,正常設定或者不需要修改的部分代碼就沒貼了):
# settings.py檔案增加配置
# 去重類的引入
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
# redis排程器的引用
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# redis是否本地化的開關
SCHEDULER_PERSIST = True
# 分布式爬蟲需要配置要通路的redis的主機
REDIS_HOST = '10.11.56.63' # 主機ip
REDIS_PORT =
ITEM_PIPELINES = {
'dushuProject.pipelines.DushuprojectPipeline': ,
# 導入依賴
'scrapy_redis.pipelines.RedisPipeline':,
}
# 延時1s(反爬蟲)
DOWMLOAD_DELAY =
# items.py檔案,即要爬取的資料字段
import scrapy
class DushuprojectItem(scrapy.Item):
title = scrapy.Field()
img_url = scrapy()
# pipelines.py檔案,未作修改
class DushuprojectPipeline(object):
def process_item(self, item, spider):
return item
# read2.py檔案(爬蟲檔案,讀書網)
# -*- coding: utf-8 -*-
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import Rule
from scrapy_redis.spiders import RedisCrawlSpider # 導入RedisCrawlSpider
class Read2Spider(RedisCrawlSpider): # 繼承的父類修改一下
name = 'read2' # 爬蟲名字
# start_urls = ['https://www.dushu.com/book/1081.html'] # 初始url
# 鍵名稱的一般規則 爬蟲名字:start_urls
redis_key = 'read2:start_urls' # 由主機提供
# 指定了頁面内,連結的提取規則,會被父類自動調用
rules = (
Rule(LinkExtractor(allow=r'/book/1081_\d+.html'), callback='parse_item', follow=False),
)
# 頁面資料解析函數
# 可以自定義,隻要保證callback的參數與這個函數名一緻即可
def parse_item(self, response):
# 每頁的圖書清單
book_list = response.xpath('//div[@class="bookslist"]//li')
for each in book_list:
i = {}
i['title'] = each.xpath('.//h3//@title').extract_first()
i['img_url'] = each.xpath('.//img/@src').extract_first()
print(i)
yield i
# 執行分布式爬蟲的步驟:
# 1. 本地運作以下指令
scrapy runspider read2.py
# 2. 主機端開啟redis服務
# 另開視窗
redis-cli
lpush redis_key start_url # 推送start_url
# 例如 lpush read2:star_url "https://www.dushu.com/book/1081.html"
遠端連接配接redis:
redis-cli -h ip -p 6379 -a password