2012-09-23 15 views
35

私はCrawlSpiderで治療を使用しているウェブサイトのクローラを作成しています。URLに基​​づいて重複したリクエストをフィルタリングする方法

Scrapyは、URLに基​​づいて重複した要求をフィルタリングする組み込みの複製要求フィルタを提供します。また、私はルール CrawlSpiderのメンバーを使ってリクエストをフィルタリングできます。私が何をしたいか

のような要求をフィルタリングすることである:私はすべてののIDを蓄積セットを持っている場合、私はすでに、今

http:://www.abc.com/p/xyz.html?id=1234&refer=4567 

NOTE: refer is a parameter that doesn't affect the response I get, so I don't care if the value of that parameter changes.

を訪問している場合は

http:://www.abc.com/p/xyz.html?id=1234&refer=5678 

この機能を実現するには、コールバック関数parse_item(私のコールバック関数)を無視することができます。

しかし、それは私がまだ必要ないときに、少なくともそのページを取得していることを意味します。

私は、それがURLに基​​づいて特定のリクエストを送信すべきではないと言うことをスクラピーに伝える方法は何ですか?

答えて

36

あなたは、あなたはそれがその

後に動作するはずsettings.py

DUPEFILTER_CLASS = 'scraper.duplicate_filter.CustomFilter' 

に正しいDUPFILTER_CLASSを設定する必要があり、重複除去のためのカスタムミドルウェアを書いて、設定

import os 

from scrapy.dupefilter import RFPDupeFilter 
from scrapy.utils.request import request_fingerprint 

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) 

でそれを追加することができます

+0

まさに私が望むもの、Thx。 – thinker007

+0

私はクモフォルダ内のファイルにコードを置くが、私はこのエラー 'dupefilter = dupefilter_cls.from_settings(設定) exceptions.AttributeErrorました:「モジュール」オブジェクトが gs'' –

+0

おかげで、この作品from_settin何の属性」を持っていませんが私のカスタムフィルタクラスから 'spider'オブジェクトにアクセスするにはどうしたらいいですか? – wolfgang

9

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が述べたように、settings.pyDUPEFILTER_CLASS定数を追加してください:

DUPEFILTER_CLASS = 'scraper.custom_filters.SeenURLFilter' 
+0

ファイルペーストはどこに置く必要がありますか? –

+0

@WilliamKinaan 'custom_filters.py'は' settings.py'と同じディレクトリにあります。しかし、私はとにかく私のために十分だったので、私はちょうど治療のデフォルトのURLフィルタを使用して終了しました。これは、カスタムフィルタの書き方を学ぶ上での練習になりました。私は内部の実装を見ていないが、より高いルックアップ性能を提供する[ブルームフィルタ](http://en.wikipedia.org/wiki/Bloom_filter)を使用していると聞いたことがある(潜在的に再訪問するコストで*いくつかの* URL)。 –

+0

ご意見ありがとうございます。また、 'scrapyのデフォルトURLフィルタ'とは何ですか?さらに、あなたはそれの公式文書を投稿するかもしれませんか?事前に感謝します –

2

https://github.com/scrapinghub/scrapylib/blob/master/scrapylib/deltafetch.py

このファイルはお役に立ちます。このファイルは、URLからユニークなデルタ取得キーのデータベースを作成します。ユーザーはscrapy.Reqeust(meta = {'deltafetch_key':uniqe_url_key})に入ります。 これにより、過去に既に訪れた重複したリクエストを回避できます。 deltafetch.py​​

 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 

などを使用して

サンプルのMongoDB実装。 id = 345 scrapy.Request(url、meta = {deltafetch_key:345}、callback = parse)

1

ここでは、私のカスタムフィルタベース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 
+1

素晴らしいですが、スパイダーベースでスパイダー経由でやるよう提案していますか? – wolfgang

関連する問題