42

我正在使用带有 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(这是我的回调函数)中忽略它来实现这个功能。

但这意味着当我不需要时,我至少仍然在获取该页面。

那么我可以告诉scrapy它不应该根据url发送特定请求的方式是什么?

4

5 回答 5

41

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

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'

它应该在那之后工作

于 2012-11-28T13:15:35.627 回答
10

在 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'
于 2013-09-15T04:56:43.693 回答
3

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

该文件可能会对您有所帮助。该文件从 url 创建一个唯一 delta fetch key 的数据库,用户传入一个 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)

于 2015-02-19T12:45:35.723 回答
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
于 2015-05-29T23:58:36.543 回答
0

在最新的scrapy中,我们可以使用默认的重复过滤器或扩展并拥有自定义的过滤器。

在蜘蛛设置中定义以下配置

DUPEFILTER_CLASS = 'scrapy.dupefilters.BaseDupeFilter'

于 2020-01-28T13:59:13.507 回答