scrapy中自定义过滤规则以及start_urls不进过滤器的问题

为什么要自定义过滤规则呢? 首先,我们需要过滤,但是不是说抓一次就不抓了,因为我们的抓取是一段时间抓取一次

自定义策略如下:

首先我试图直接继承RFPDupeFilter

在settings.py同级的目录下新建dupefilter.py文件,按照网上说的方法,写了内容如下

from scrapy.dupefilter import RFPDupeFilter
import hashlib
from scrapy.utils.request import request_fingerprint
from scrapy.dupefilter import BaseDupeFilter


class URLFilter(RFPDupeFilter):

    def __init(self):
        RFPDupeFilter.__init__(self)

    def request_seen(self, request):

        fp = self.request_fingerprint(request)
        added = self.server.sadd(self.key, fp)

        return added == 0

在settings.py中添加

DUPEFILTER_CLASS = 'CrawlBaiduMobile.dupefilter.URLFilter'

但是启动spider会报如下错误:

ValueError: ("Failed to instantiate dupefilter class '%s': %s", 'CrawlBaiduMobile.dupefilter.URLFilter', TypeError("__init__() got an unexpected keyword argument 'debug'",))

或者报

ValueError: ("Failed to instantiate dupefilter class '%s': %s", 'CrawlBaiduMobile.dupefilter.URLFilter', TypeError("__init__() got an unexpected keyword argument 'key'",))

含义其实也很明显, 调用RFPDupeFilter的构造方法时出错了,可能是我的版本比较新吧。

于是我找到了RFPDupeFilter的源码,写了一个基本和它一致的, 但是过滤策略有些不同

from scrapy_redis.dupefilter import RFPDupeFilter
from scrapy_redis.connection import get_redis_from_settings
from scrapy.dupefilters import BaseDupeFilter
from scrapy.utils.request import request_fingerprint
from scrapy_redis import defaults
import hashlib

class URLFilter(BaseDupeFilter):

    def __init__(self, server, key, debug=False):
        self.server = server
        self.key = key
        self.debug = debug
        self.logdupes = True
        self.timeout = 60*60*24*10    #设置过期时间10天,10天内重复的url不重复抓取

    @classmethod
    def from_settings(cls, settings):
        server = get_redis_from_settings(settings)
        key = defaults.DUPEFILTER_KEY % {'timestamp': int(time.time())}
        debug = settings.getbool('DUPEFILTER_DEBUG')
        return cls(server, key=key, debug=debug)

    @classmethod
    def from_crawler(cls, crawler):
        return cls.from_settings(crawler.settings)

    def request_seen(self, request):
        key = self.request_fingerprint(request)
        if self.server.get(key):
            return True
        else:
            self.server.set(key, 1, self.timeout) 

    def request_fingerprint(self, request):
        return hashlib.md5(request.url).hexdigest()

我依然用了redis存储缓存key,但是用的字符串,没有再用有序集合,因为我们的策略是一段时间内不重复抓取,所以需要给抓取过的key设置一个缓存时间

此外,缓存key的生成方式也做了修订,改用了md5算法生成了一个40位的key

 

在实验过程中发现一个问题,start_urls中的url没有进这个过滤器

首先看下start_urls中的初始url是如何被构造成Request的

def start_requests(self):
    for url in self.start_urls:
        yield self.make_requests_from_url(url)

def make_requests_from_url(self, url):
    return Request(url, dont_filter=True)

在start_requests中会将start_urls里面的url(当然也可以是redis中的),通过make_requests_from_url方法构造成Request对象

但是传参dont_filter=True,也就是不经过过滤器的,所以默认情况下,初始start_urls中的url不会经过上面配置的过滤器

可以在spider中覆写这个方法, 设置dont_filter=False:

class CrawlBaiduMobile(RedisCrawlSpider):

    #some other code

    def make_requests_from_url(self, url):
        return Request(url, dont_filter=False)

此外,图片下载的Request也没有进这个过滤器

配置页面中的图片下载:

class CrawlImagePipeline(ImagesPipeline):

    def get_media_requests(self, item, info):
        if isinstance(item, CrawlImageItem):
            for image_url in item['image_urls']:
                self.default_headers['referer'] = image_url
                yield Request(image_url, headers=self.default_headers, dont_filter=False)

这里也用了yield Request,  但是这个Request不会进入到上面配置的过滤器中, 即使给了dont_filter=False,当然更具体是什么原因,我没有深究了, 因为我们的系统对于抓取图片有不同的过滤规则,的确也不需要经过这个过滤器

图片下载应该是有一套自己的排重策略,就是用过期时间,可以在settings.py中配置,

IMAGES_EXPIRES = 90   #90天内重复的图片不会再下载, 如果服务重启了,之前保存的下载过的图片会重新下载

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分布式爬虫是指通过多个节点同时运行爬虫程序,提高数据抓取的效率。scrapy-redis是一个用于实现分布式爬虫的Scrapy扩展库,它可以将爬取的URL任务队列存储在Redis,从而实现多个节点之间的任务共享。 scrapy-redis的使用可以分为以下几个步骤: 1. 首先,我们需要在爬虫程序引入scrapy_redis库,并将原来继承的scrapy.Spider类改为引入的RedisSpider类。这样就可以使用RedisSpider的功能了。 2. 其次,我们需要配置Redis连接信息,在settings.py文件设置REDIS_HOST和REDIS_PORT参数,来连接Redis数据库。 3. 然后,在爬虫的start_urls定义初始URL,这些URL将被添加到Redis队列作为初始任务。可以使用redis-cli命令行工具来查看队列URL任务。 4. 接下来,我们可以使用scrapy_redis提供的调度器(Scheduler)和去重过滤器(DupeFilter)类来管理URL任务队列。调度器类scheduler.py用于调度URL任务,而去重过滤器dupefilter.py用于去除重复的URL,避免重复抓取。 5. 最后,我们可以使用scrapy-redis提供的pipeline来存储抓取到的数据到MySQL数据库。可以自定义一个Pipeline类,继承scrapy_redis.pipelines.RedisPipeline,并在settings.py文件启用该Pipeline。 综上所述,分布式爬虫scrapy-redis与MySQL的使用包括引入scrapy_redis库、配置Redis连接信息、定义初始URL、使用调度器和去重过滤器管理URL任务队列,以及使用自定义的Pipeline将数据存储到MySQL数据库。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [scrapy 分布式爬虫全集](https://download.csdn.net/download/bobbykey/10291995)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Scrapy基于scrapy_redis实现分布式爬虫部署](https://blog.csdn.net/weixin_29137997/article/details/113682107)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值