首页 文章

如何在scrapy中基于url过滤重复请求

提问于
浏览
38

我正在为使用CrawlSpider scrapy的网站编写一个爬虫 .

Scrapy提供了一个内置的重复请求过滤器,可根据URL过滤重复的请求 . 此外,我可以使用CrawlSpider的规则成员过滤请求 .

我想要做的是过滤以下请求:

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

如果我已经访问过

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

注意:refer是一个不影响我得到的响应的参数,所以我不在乎该参数的值是否发生变化 .

现在,如果我有一个累积所有ID的集合,我可以在我的回调函数parse_item(这是我的回调函数)中忽略它来实现此功能 .

但这意味着当我不需要时,我至少仍然会 grab 那个页面 .

那么我告诉scrapy它不应该基于url发送特定请求的方式是什么?

4 回答

  • 10

    您可以编写自定义中间件以进行重复删除,并将其添加到设置中

    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)
    

    然后,您需要在settings.py中设置正确的DUPFILTER_CLASS

    DUPEFILTER_CLASS = 'scraper.duplicate_filter.CustomFilter'
    

    它应该在那之后工作

  • 39

    在ytomar的带领下,我编写了这个过滤器,它基于通过检查内存集已经看到的URL进行过滤 . 我是一个Python菜鸟让我知道如果我搞砸了什么,但似乎工作正常:

    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'
    
  • 3

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

    这个文件可以帮到你 . 此文件从url创建唯一delta获取密钥的数据库,用户在scrapy中传递.Reqeust(meta = {'deltafetch_key':uniqe_url_key}) . 这样,您就可以避免过去曾访问过的重复请求 .

    使用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)

  • 1

    这是我的自定义过滤器基于scrapy 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

    被视为相同的网址 . 但

    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
    

相关问题