scrapy 自帶了去重方案,通過rfpdupefilter類完成去重,檢視原始碼。
def request_seen(self, request):
fp = self.request_fingerprint(request)
if fp in self.fingerprints:
return true
self.fingerprints.add(fp)
if self.file:
self.file.write(fp + os.linesep)
def request_fingerprint(self, request):
return request_fingerprint(request)
def request_fingerprint(request, include_headers=none):
if include_headers:
include_headers = tuple(to_bytes(h.lower())
for h in sorted(include_headers))
cache = _fingerprint_cache.setdefault(request, {})
if include_headers not in cache:
fp = hashlib.sha1()
fp.update(to_bytes(request.method))
fp.update(to_bytes(canonicalize_url(request.url)))
fp.update(request.body or b'')
if include_headers:
for hdr in include_headers:
if hdr in request.headers:
fp.update(hdr)
for v in request.headers.getlist(hdr):
fp.update(v)
cache[include_headers] = fp.hexdigest()
return cache[include_headers]
rfpdupefilter定義了request_seen()方法,將request的指紋資訊sha1(method+url+body+header)整體寫入set()進行去重。
這種方式去重的比例較小。
下面我們定製過濾器,僅根據request的url進行去重。
from scrapy.dupefilters import rfpdupefilter
class urlfilter(rfpdupefilter):
""" 只根據url去重"""
def __init__(self, path=none, debug=false):
self.urls_seen = set()
rfpdupefilter.__init__(self, path)
def request_seen(self, request):
if request.url in self.urls_seen:
return true
else:
self.urls_seen.add(request.url)
配置setting.py
dupefilter_class = '專案名.檔名.urlfilter'
這種去重方式,儲存著set中的資訊在爬蟲執行結束就會消失。下次排程爬蟲的時候還是會繼續爬去此次爬過的url。
為了實現增量爬蟲,可以利用redis的set()快取爬過的url資料。
1.自定義過濾器,在爬資料之前,校驗該url是否爬取過
from scrapy.dupefilters import rfpdupefilter
class urlredisfilter(rfpdupefilter):
""" 只根據url去重"""
def __init__(self, path=none, debug=false):
rfpdupefilter.__init__(self, path)
self.dupefilter = urlfilterandadd()
def request_seen(self, request):
# 校驗,新增2行**
if self.dupefilter.check_url(request.url):
return true
#保留中間頁面的去重規則不變,不然爬蟲在執行過程中容易出現死迴圈
fp = self.request_fingerprint(request)
if fp in self.fingerprints:
return true
self.fingerprints.add(fp)
if self.file:
self.file.write(fp + os.linesep)
class urlfilterandadd(object):
def __init__(self):
redis_config =
pool = connectionpool(**redis_config)
self.pool = pool
self.redis = strictredis(connection_pool=pool)
self.key = "spider_redis_key"
def url_sha1(self, url):
fp = hashlib.sha1()
fp.update(canonicalize_url(url).encode("utf-8"))
url_sha1 = fp.hexdigest()
return url_sha1
def check_url(self, url):
sha1 = self.url_sha1(url)
#此處只判斷url是否在set中,並不新增url資訊,
#防止將起始url 、中間url(比如列表頁的url位址)寫入快取中,
i***ist = self.redis.sismember(self.key, sha1)
return i***ist
def add_url(self, url):
sha1 = self.url_sha1(url)
added = self.redis.sadd(self.key, sha1)
return added
注意:urlfilter中只校驗爬蟲是否存在,不快取url資料
2.修改pipeline 在資料爬完後將url放入redis中去重,避免將中間鏈結也快取了
在setting中配置:class myspiderpipeline(object):
print("add>>url:", item['crawl_url'])def __init__(self):
self.dupefilter = urlfilterandadd()
def process_item(self, item, spider):
# ,在資料爬完後將url放入redis去重
print("add>>url:", item['crawl_url'])
self.dupefilter.add_url(item['crawl_url'])
return item
self.dupefilter.add_url(item['crawl_url'])
return item
item_pipelines =
dupefilter_class = '專案名.檔名.urlredisfilter'
按照目前的方式,redis中的資料會一直膨脹,後續在優化。 用redis實現秒殺
今日在研究秒殺系統,用資料庫的樂觀鎖可以實現,但是在高併發下可能並不好,所以就想到了快取系統redis,因為redis本身也有鎖機制,廢話不多說,直接上 請大神指點不足的地方。class a public class myrunnable implements runnable override p...
用Redis實現Session功能,實現單點登入
redis是乙個開源的使用ansi c語言編寫 支援網路 可基於記憶體亦可持久化的日誌型 key value資料庫,並提供多種語言的api 維基百科 一般開發中使用者狀態使用session或者cookie,兩種方式各種利弊。session 在inproc模式下容易丟失,並且引起併發問題。如果使用sq...
用redis實現的小遊戲設計
前段時間接了乙個h5遊戲的後端開發任務,需求比較簡單,就是在大會場裡,幾百 上千人分成若干組,在一段時間裡同時搖手機,實時顯示當前排名,最後看哪個組搖的最快,哪個人搖的最快。由於是所有使用者同時搖手機,而且一秒鐘之內要搖5 10下,假設一千人同時搖,可能在一秒鐘內會有5000至10000次的寫入請求...