如何根据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