开发者社区> kekefund> 正文

Scrapy结合Redis实现增量爬取

简介: Scrapy适合做全量爬取,但是,我们不是一次抓取完就完事了。很多情况,我们需要持续的跟进抓取的站点,增量抓取是最需要的。 Scrapy与Redis配合,在写入数据库之前,做唯一性过滤,实现增量爬取。
+关注继续查看

Scrapy适合做全量爬取,但是,我们不是一次抓取完就完事了。很多情况,我们需要持续的跟进抓取的站点,增量抓取是最需要的。
Scrapy与Redis配合,在写入数据库之前,做唯一性过滤,实现增量爬取。


一、官方的去重Pipeline

官方文档中有一个去重的过滤器:

from scrapy.exceptions import DropItem

class DuplicatesPipeline(object):

    def __init__(self):
        self.ids_seen = set()

    def process_item(self, item, spider):
        if item['id'] in self.ids_seen:
            raise DropItem("Duplicate item found: %s" % item)
        else:
            self.ids_seen.add(item['id'])
            return item

官方的这个过滤器的缺陷是只能确保单次抓取不间断的情况下去重,因为其数据是保存在内存中的,当一个爬虫任务跑完后程序结束,内存就清理掉了。再次运行时就失效了。

二、基于Redis的去重Pipeline

为了能够多次爬取时去重,我们考虑用Redis,其快速的键值存取,对管道处理数据不会产生多少延时。

#pipelines.py

import pandas as pd
import redis
redis_db = redis.Redis(host=settings.REDIS_HOST, port=6379, db=4, password=settings.REDIS_PWD)
redis_data_dict = "f_uuids"

class DuplicatePipeline(object):
    """
    去重(redis)
    """

    def __init__(self):
        if redis_db.hlen(redis_data_dict) == 0:
            sql = "SELECT uuid FROM f_data"
            df = pd.read_sql(sql, engine)
            for uuid in df['uuid'].get_values():
                redis_db.hset(redis_data_dict, uuid, 0)

    def process_item(self, item, spider):

        if redis_db.hexists(redis_data_dict, item['uuid']):
             raise DropItem("Duplicate item found:%s" % item)

        return item
  1. 首先,我们定义一个redis实例: redis_db和redis key:redis_data_dict。
  2. 在DuplicatePipeline的初始化函数init()中,对redis的key值做了初始化。当然,这步不是必须的,你可以不用实现。
  3. 在process_item函数中,判断redis的hash表中存在该值uuid,则为重复item。
    至于redis中为什么没有用list而用hash? 主要是因为速度,hash判断uuid是否存在比list快好几个数据级。
    特别是uuid的数据达到100w+时,hash的hexists函数速度优势更明显。

最后别忘了在settings.py中加上:

# Configure item pipelines
# See http://scrapy.readthedocs.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
    'fund_spider.pipelines.DuplicatePipeline': 200,
     #'fund_spider.pipelines.MySQLStorePipeline': 300,
}

三、总结

本文不是真正意义上的增量爬取,而只是在数据存储环节,对数据唯一性作了处理,当然,这样已经满足了大部分的需求。
后续我会实现不需要遍历所有的网页,判断抓取到所有最新的item,就停止抓取。敬请关注!

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Redis学习4:List数据类型、拓展操作、实现日志等
注意点:对存储空间的顺序进行分析!
35 0
Redis学习3:hash类型操作、拓展操作、实现购物等
首先可以理解成一个redis里面有一个小的redis。同时要注意引入了一个field的名字。
39 0
2021年你还不会Shiro?----10.使用redis实现Shiro的缓存
上一篇文章已经总结了使用ehCache来实现Shiro的缓存管理,步骤也很简单,引入依赖后,直接开启Realm的缓存管理器即可。如果使用Redis来实现缓存管理其实也是一样的,我们也是需要引入redis的依赖,然后开启缓存传入自定义的redis的缓存管理器就行。区别是我们需要为自定义的redis缓存管理器提供自定义的缓存管理类。这个缓存管理类中需要使用到redisTemplate模板,这个模板我们也是需要自己定义。
120 0
浅谈Redis实现分布式锁
浅谈Redis实现分布式锁
109 0
异步结果通知实现——基于Redis实现,我这操作很可以
前段时间,我在内存中实现了一个简单异步通知框架。但由于没有持久化功能,应用重启就会导致数据丢失,且不支持分布式和集群。今天这篇笔记,引入了 Redis 来解决这些问题,以下是几点理由: 数据结构丰富,支持 List、Sorted Set 等 具有持久化功能,消息的可靠性能得到保证 高可用性,支持单机、主从、集群部署 项目中已使用,接入成本更低 基于 Redis 实现延时队列也有几种方法,展开详细讲讲。
113 0
thinkphp+redis实现秒杀功能
thinkphp+redis实现秒杀功能
93 0
PHP结合redis实现点赞功能
PHP结合redis实现点赞功能
48 0
php结合redis实现高并发下的抢购、秒杀功能的实例
php结合redis实现高并发下的抢购、秒杀功能的实例
114 0
分布式锁中-基于 Redis 的实现如何防重入
分布式锁中-基于 Redis 的实现如何防重入
97 0
+关注
kekefund
FinTech
文章
问答
视频
文章排行榜
最热
最新
相关电子书
更多
Redis&MongoDB的同步、迁移以及混合云场景构建
立即下载
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载