美文网首页Python爬虫
Scrapy结合Redis实现增量爬取

Scrapy结合Redis实现增量爬取

作者: kekefund | 来源:发表于2016-08-24 16:10 被阅读2137次

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,就停止抓取。敬请关注!

相关文章

  • Scrapy结合Redis实现增量爬取

    Scrapy适合做全量爬取,但是,我们不是一次抓取完就完事了。很多情况,我们需要持续的跟进抓取的站点,增量抓取是最...

  • 使用scrapy-deltafetch实现增量爬取

    Scrapy学习笔记-使用scrapy-deltafetch实现增量爬取 前言 在之前的文章中我们都是对目标站点进...

  • Python爬虫第十天:Scrapy-Redis|分布式爬虫

    一:Scrapy-Redis 概述:是实现Scrapy分布式爬取而提供了一些以redis为基础的组件。 组件包含...

  • 分布式爬虫

    分布式部署就是实现多台电脑共同爬取数据 安装scrapy-redis pip install scrapy-red...

  • scrapy 实现去重,存入redis(增量爬取)

    官方去重:scrapy官方文档的去重模块,只能实现对当前抓取数据的去重,下面是官方 API 当有一天需求变了,在你...

  • scrapy中间件实现增量爬虫

    前言 scrapy爬取网站数据的时候,一般第一次爬取为全量爬取,以后需要的都是增量爬取,或者爬取中断之后需要继续爬...

  • scrapy-deltafetch实现增量爬取

    前言 在之前的文章中我们都是对目标站点进行全量爬取,只要爬虫run起来就会对所有的链接都爬取一遍,这其实是很傻的做...

  • 2018-08-14

    Windows环境下Scrapy的断点续爬、增量爬取、断网急救 (2017-10-27 22:50:32) 转载▼...

  • Redis基本使用

    去年大概九月份时,使用Scrapy+Redis实现分布式爬取数据,然后接触到Redis,并查看源码了解到Redis...

  • Scrapy-Redis分布式爬取自如网(一)

    继上次Scrapy爬取猫眼电影之后,这几天学习了Scrapy-Redis分布式来提高爬取效率,也算是停留在舒适圈一...

网友评论

  • 七月宋:按照楼主的方法,我在Downloader Middleware 中写了 process_request(request, spider) 方法, 改用request.url 判断,if redis_db.hexists(redis_data_dict, request.url): raise IgnoreRequest() #忽略请求 else: return None 感谢楼主思路
    kekefund:@七月宋 :+1:
  • 七月宋:你好,上午用楼主的方法试了一下,没弄明白,代码可以跑起来。 我理解的楼主的思路是把详情页全部请求下来,在入库的时候判断有木有重复,这样实现去重,不知道对不对?
    kekefund:@七月宋 是这个意思
  • sunoath:df = pd.read_sql(sql, engine),第二个参数是什么意思?
    kekefund:查看pandas 的read_sql接口文档
  • Traim:>>>不需要遍历所有的网页,判断抓取到所有最新的item,就停止抓取。
    现在想做这个功能。不知道怎么实现。能指点下思路吗😅
    kekefund:@Traim 对的
    Traim:@自然晟 哦。明白了。这是建立在有时间排序的机制上的,如果没有这前提,只能先全爬,然后入库的时候查重了吧。
    kekefund:@Traim 抓取时先从时间最远的item开始抓,时间由远及近,item存到数据库。第二次增量抓取时,对比数据库item的时间,先移到数据库中的最新时间所对应的页面,然后由远及近的抓取。

本文标题:Scrapy结合Redis实现增量爬取

本文链接:https://www.haomeiwen.com/subject/axlosttx.html