去重原理:
至關因而寫了集合self.vister_urls=set(),把全部的url放進去當執行yield Requets的時候就會執行,進行判斷,看是否這個訪問的url在這個集合裏面,若是在的話,就不添加進去了redis
from scrapy.utils.request import request_fingerprint##進行加密,url的惟一標識scrapy
每一次yield Request的時候,就會執行settings裏面的去重
從from_settings開始執行,返回的時候,就執行下面的requets_seen方法ide
settings:
#執行自定義的去重規則
DUPEFILTER_CLASS='scrapyproject1.dupliter.Self_Dupliter'加密
spider:url
#yield Request(url=page_url, callback=self.parse,dont_filter=True)##每一次requets的時候,就會執行去重的方法,不許詢去重規則,若是要遵循的話,那麼應該爲false
要遵循去重規則,就要改爲dont_filter=False,或者不添加,默認爲False
原理分析:spa
from scrapy.dupefilter import BaseDupeFilter
from scrapy.utils.request import request_fingerprint##進行加密,url的惟一標識,會進行加密處理
'''
在scrapy裏面有一個惟一標識
http://xxx.com/?k1=v1&k2=v2
http://xxx.com/?k2=v2&k1=v1
若是是md5進行加密的話,這兩個url是不同的,可是這兩個url是相同的
可是scrapy裏面有一個方法,能夠辨別出兩個相同的url出來
request_fingerprint(放在裏面進行加密,若是是相同的打印出來也是相同的)
'''
##去重
class Self_Dupliter(BaseDupeFilter):
def __init__(self):
self.vister_urls=set()
##設置url元祖
@classmethod
def from_settings(cls, settings):
print('最開始')
return cls()
# def request_seen(self, request):###傳入的requets裏面有url,能夠直接取出來
# print('執行去重規則')
# if request.url in self.vister_urls:
# return True
# self.vister_urls.add(request.url)
# return False
def request_seen(self, request): ###傳入的requets裏面有url,能夠直接取出來
print('執行去重規則')
print(request.url)
fd=request_fingerprint(request)##進行了加密處理,長度同樣
if fd in self.vister_urls:##若是訪問的url在這裏的話,就返回true,不執行
print('存在')
print(request.url)
return True
self.vister_urls.add(fd)
##爬蟲開始的時候
def open(self): # can return deferred
print('開始')
##redis,爬蟲結束
def close(self, reason): # can return a deferred
print('結束')
##記錄日誌的時候
def log(self, request, spider): # log that a request has been filtered
print('記錄日誌')
'''
可讓他每次來不執行init方法
直接是下面的方法,因此init裏面定義的set能夠一直加值,在進行判斷,至關因而一個存放url(不重複)集合
執行順序:
最開始執行settings(有執行去重類,導入模塊的時候)
在執行parse方法,若是settings裏面配置了去重的類的話,那麼每yield Requets的時候,就會執行這個自定義的去重類:
去重類執行順序:先執行from_seen,在執行open,在執行request_seen(屢次執行,每yield Request一次的話,就執行一次這個方法),最後執行close
'''
鏈接redis去重處理(放進redis集合裏面)
爬蟲裏面:
from scrapy.http.request import Request
def parse(self, response):
print('執行操做')
# obj=response.xpath('//*[@id="dig_lcpage"]/ul/li/a[re:test(@class,"ct_pagepa")]/@href').extract()
obj=response.xpath('//*[@id="dig_lcpage"]/ul/li/a[re:test(@href,"/all/hot/recent/(\d+)")]/@href').extract()
for i in obj:
# print(i)
page='https://dig.chouti.com'+i
yield Request(url=page,callback=self.parse)#dont_filter=True是不執行去重的,當爲false是執行去重的
settings裏面:日誌
DUPEFILTER_CLASS='scrapy_pro.dupfliter.DupFliter'
去重類裏面:
from scrapy.dupefilter import BaseDupeFilter
from scrapy.utils.request import request_fingerprint
import redis
class DupFliter(BaseDupeFilter):
def __init__(self):
self.dupdic=redis.Redis(host='127.0.0.1',port=6379)
# def request_seen(self,request):
# url=request_fingerprint(request)
# if url in self.dupdic:
# return True
# self.dupdic.add(url)
# print('添加成功',request.url)
def request_seen(self,request):
url=request_fingerprint(request)
print('執行去重')
if url==1:
self.dupdic.sadd('scrapy_urls', request.url) ##作判斷,看是不是相等的
print('添加成功', request.url)
return False
print('已經存在',request.url)
return True
# 若是是添加成功的haul,那麼久返回fasle,不作處理,若是返回true就會執行下一個yield