如何根据在scrapy URL过滤重复请求(how to filter duplicate requ

2019-06-18 06:44发布

我写一个履带使用scrapy与CrawlSpider网站。

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

注:指的是不影响我得到的响应参数,所以我不在乎如果该参数的值更改。

现在,如果我有一组聚集所有的ID,我可以忽视它在我的回调函数parse_item(这是我的回调函数)来实现这一功能。

但是,这将意味着我仍然至少获取该网页,当我不需要。

那么,什么是我可以告诉scrapy,它不应该发送基于URL中的特定请求的方式吗?

Answer 1:

你可以写重复的去除定制的中间件和在设置中添加它

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'

它应该在这之后的工作



Answer 2:

继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'


Answer 3:

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

该文件可能会帮助您。 此文件创建唯一的增量的一个数据库中获取从URL键,用户通过在一个scrapy.Reqeust(甲基= {“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,元= {deltafetch_key:345},回调=解析)



Answer 4:

这里是scrapy 0.24.6我的自定义过滤器基地。

在此过滤器,它只在乎ID在URL中。 例如

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


文章来源: how to filter duplicate requests based on url in scrapy