add filters module

--HG--
extra : convert_revision : svn%3Ab85faa78-f9eb-468e-a121-7cced6da292c%40890
This commit is contained in:
Daniel Grana 2009-02-19 19:53:30 +00:00
parent 0e98526daa
commit 071aa71b68
2 changed files with 127 additions and 0 deletions

View File

@ -0,0 +1,86 @@
from pydispatch import dispatcher
from scrapy.core import signals
from scrapy.http import Request
from scrapy.core.exceptions import NotConfigured, IgnoreRequest
from scrapy.utils.request import request_fingerprint
from scrapy.utils.misc import load_object
from scrapy.conf import settings
from scrapy import log
class BaseFilter(dict):
"""Base class defining the duplicates requests filtering api"""
def __init__(self, *args, **kwargs):
super(BaseFilter, self).__init__(*args, **kwargs)
dispatcher.connect(self.open, signals.domain_open)
dispatcher.connect(self.close, signals.domain_closed)
def open(self, domain):
"""Called when a domain starts"""
raise NotImplementedError()
def close(self, domain):
"""Called when a domain is closed"""
raise NotImplementedError()
def add(self, domain, request):
"""Called to check if a request was already seen, and adds it to seen set.
returns True if not seen before, or False otherwise.
"""
raise NotImplementedError()
def has(self, domain, request):
"""Called to check if a request was seen but doesnt add request to seen set."""
raise NotImplementedError()
class SimplePerDomainFilter(BaseFilter):
"""Filter out a request if already seen for same domain"""
def open(self, domain):
"""Initialize the resources needed for filtering for this domain"""
self[domain] = set()
def close(self, domain):
"""Remove the resources reserved for filtering for this domain"""
del self[domain]
def add(self, domain, request):
"""Add the fingerprint of a request to the domain set if a equivalent fingerprint has not been added.
This method will return true if the fingerprint was added and false otherwise.
"""
fp = request_fingerprint(request)
if fp not in self[domain]:
self[domain].add(fp)
return True
return False
def has(self, domain, request):
fp = request_fingerprint(request)
return fp in self[domain]
class NullFilter(dict):
def open(self, domain):
pass
def close(self, domain):
pass
def add(self, domain, request):
return True
def has(self, domain, request):
return None
try:
duplicatesfilter
except NameError:
clspath = settings.get('DUPLICATESFILTER_FILTERCLASS')
cls = load_object(clspath) if clspath else NullFilter
duplicatesfilter = cls()

View File

@ -0,0 +1,41 @@
import unittest
from scrapy.http import Request
from scrapy.core.filters import SimplePerDomainFilter, NullFilter
class SimplePerDomainFilterTest(unittest.TestCase):
def test_filter(self):
domain = 'scrapytest.org'
filter = SimplePerDomainFilter()
filter.open(domain)
assert domain in filter
r1 = Request('http://scrapytest.org/1')
r2 = Request('http://scrapytest.org/2')
r3 = Request('http://scrapytest.org/2')
assert not filter.has(domain, r1)
assert filter.add(domain, r1)
assert filter.has(domain, r1)
assert filter.add(domain, r2)
assert not filter.add(domain, r3)
filter.close(domain)
assert domain not in filter
class NullFilterTest(unittest.TestCase):
def test_filter(self):
domain = 'scrapytest.org'
filter = NullFilter()
filter.open(domain)
r1 = Request('http://scrapytest.org/1')
assert not filter.has(domain, r1)
assert filter.add(domain, r1)
assert not filter.has(domain, r1)
filter.close(domain)