如何根据scrapy中的URL过滤重复的请求

我正在为使用Scraw和CrawlSpider的网站编写爬虫程序。

Scrapy提供了一个内置的重复请求filter,它根据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的集合,我可以忽略它在我的callback函数parse_item (这是我的callback函数)来实现这个function。

但是这意味着我至less还可以拿到那个页面,当我不需要的时候。

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

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

 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' 

它应该在那之后工作

在ytomar的领导下,我编写了这个filter,纯粹基于已经通过检查内存集已经看到的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提到的,一定要将DUPEFILTER_CLASS常量添加到settings.py

 DUPEFILTER_CLASS = 'scraper.custom_filters.SeenURLFilter' 

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

这个文件可能会帮助你。 此文件从url创build一个唯一的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)

这是我在scrapy 0.24.6上的自定义filter的基础。

在这个filter中,它只关心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