CrawlSpiderでScrapyを使用してWebサイトのクローラーを作成しています。
Scrapyには、URLに基づいて重複リクエストをフィルタリングする組み込みの重複リクエストフィルターが用意されています。また、CrawlSpiderのrulesメンバーを使用してリクエストをフィルタリングできます。
私がしたいのは、次のようなリクエストをフィルタリングすることです:
http:://www.abc.com/p/xyz.html?id=1234&refer=5678
私がすでに訪れた場合
http:://www.abc.com/p/xyz.html?id=1234&refer=4567
注:参照は、取得した応答に影響を与えないパラメーターであるため、そのパラメーターの値が変更されてもかまいません。
ここで、すべてのidsを累積するセットがある場合、コールバック関数parse_item(これは私のコールバック関数です)この機能を実現します。
しかし、それは、必要がない場合でも、少なくともそのページをフェッチしていることを意味します。
では、URLに基づいて特定のリクエストを送信してはならないことを私に通知する方法を教えてください。
重複削除用のカスタムミドルウェアを作成し、設定に追加できます
import os
from scrapy.dupefilter import RFPDupeFilter
class CustomFilter(RFPDupeFilter):
"""A dupe filter that considers specific ids in the url"""
def __getid(self, url):
mm = url.split("&refer")[0] #or something like that
return mm
def request_seen(self, request):
fp = self.__getid(request.url)
if fp in self.fingerprints:
return True
self.fingerprints.add(fp)
if self.file:
self.file.write(fp + os.linesep)
次に、settings.pyで正しいDUPFILTER_CLASSを設定する必要があります
DUPEFILTER_CLASS = 'scraper.duplicate_filter.CustomFilter'
それはその後動作するはずです
Ytomarの先導に続いて、メモリ内のセットを確認することで既に表示されているURLのみに基づいてフィルタリングするこのフィルターを作成しました。私はPython noobですので、何かを台無しにしたかどうかを知らせてください。しかし、問題なく動作しているようです:
from scrapy.dupefilter import RFPDupeFilter
class SeenURLFilter(RFPDupeFilter):
"""A dupe filter that considers the URL"""
def __init__(self, path=None):
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)
Ytomarが述べたように、必ずDUPEFILTER_CLASS
定数をsettings.py
に追加してください。
DUPEFILTER_CLASS = 'scraper.custom_filters.SeenURLFilter'
https://github.com/scrapinghub/scrapylib/blob/master/scrapylib/deltafetch.py
このファイルが役立つ場合があります。このファイルは、ユーザーがscrapy.Reqeust(meta = {'deltafetch_key':uniqe_url_key})に渡すURLから一意のデルタフェッチキーのデータベースを作成します。これにより、過去にアクセスしたリクエストの重複を回避できます。
Deltafetch.pyを使用したmongodb実装のサンプル
if isinstance(r, Request):
key = self._get_key(r)
key = key+spider.name
if self.db['your_collection_to_store_deltafetch_key'].find_one({"_id":key}):
spider.log("Ignoring already visited: %s" % r, level=log.INFO)
continue
Elif isinstance(r, BaseItem):
key = self._get_key(response.request)
key = key+spider.name
try:
self.db['your_collection_to_store_deltafetch_key'].insert({"_id":key,"time":datetime.now()})
except:
spider.log("Ignoring already visited: %s" % key, level=log.ERROR)
yield r
例えば。 id = 345 scrapy.Request(url、meta = {deltafetch_key:345}、callback = parse)
これは、スクレイピー0.24.6に基づいたカスタムフィルターベースです。
このフィルターでは、URLのidのみが対象になります。例えば
http://www.example.com/products/cat1/1000.html?p=1
http://www.example.com/products/cat2/1000.html?p=2
同じURLとして扱われます。だが
http://www.example.com/products/cat2/all.html
しない。
import re
import os
from scrapy.dupefilter import RFPDupeFilter
class MyCustomURLFilter(RFPDupeFilter):
def _get_id(self, url):
m = re.search(r'(\d+)\.html', url)
return None if m is None else m.group(1)
def request_fingerprint(self, request):
style_id = self._get_id(request.url)
return style_id
最新のスクレイピーでは、デフォルトの複製フィルターを使用するか、拡張してカスタムフィルターを作成できます。
スパイダー設定で以下の設定を定義します
DUPEFILTER_CLASS = 'scrapy.dupefilters.BaseDupeFilter'