[Python3.4]通过Redis利用BloomFilter实现数据去重

本文介绍了在爬虫项目中如何有效避免重复爬取已访问的网页链接,通过使用Redis作为内存数据库缓存已爬取链接,并结合Bloom Filter减少磁盘读写操作,提升整体性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写爬虫的时候需要解决的一个很重要的问题就是需要判断得来的新链接是否之前已经爬过。如果已经爬过,则没有必要再爬。我之前采用的是非常笨拙的方法,就是把所有已经爬过的地址放在mysql的一张表中,但是问题在于,这样每一个新链接到来,都会查询一次是否该链接在表格中。这样的话,单单查询过程就会耗费磁盘大量的读写性能。而且实际运行的过程中也发现,磁盘的读取速率是写入速率的10倍以上,这显然是不可接受的。
一个可行的改进方案是使用内存数据库作为mysql的缓存。这里选用的是redis,是一种键值型数据库。通过将需要频繁查询的内容读入Redis,这样可以直接通过redis查询是否该链接已经存在,从而避免了直接从磁盘读取数据,提高读写性能。

——————————资料库————————————
●redis官网 点我
●然而,redis官方并不支持windows(你们这是对软狗的歧视,哼!(╯‵□′)╯︵┻━┻)所以像我这样想在win下使用的,可以去找Microsoft Open Tech group在github下的一个64位版本。 点我点我
●基础设置教程:点我点我点我
●指令教程(bloomfilter主要通过setbit和getbit来实现)点我
——————————↑↑↑↑↑↑————————————

有个问题是,把所有数据都读入内存是不可行的,因为数据量太大,而内存太小。所以这就需要bloomfilter出场了. 简单的说,bloomfilter是通过多个hash函数,将字符串映射到不同的比特位。通过查询相应的比特位上的值是否全为1,来判断该数据是否已存入数据库中。值得注意的是,bloomfilter是有出错概率的。简单的说就是:
如果bloomfilter判断不存在,则一定不存在
如果bloomfilter判断存在,则可能不存在
看完发现简直是为爬虫量身定制啊有没有!对于爬虫而言,出错的代价微乎其微,大不了少爬几个就是了,反正不会重复爬。

bloomfilter介绍:这里

对于python2.7来说,好像有个叫pybloomfilter的库可以用。但那个是单线程的,当需要多线程合作时就不行了,而且不太适合3.4版本。所以我对网上别人写的针对3.4版本的小程序稍加改进,使之能够适合redis.

import redis

class SimpleHash():
    def __init__(self,cap,seed):
        self.cap=cap
        self.seed=seed
    def hash(self,value):
        ret=0
        for i in range(value.__len__()):
            ret+=self.seed*ret+ord(value[i])
        return ((self.cap-1) & ret)

class BloomFilter():
    def __init__(self):
        self.bit_size=1<<25
        self.seeds=[5,7,11,13,31,37,61]
        self.r=redis.StrictRedis(host='127.0.0.1',port=6379,db=0)
        self.hashFunc=[]
        for i in range(self.seeds.__len__()):
            self.hashFunc.append(SimpleHash(self.bit_size,self.seeds[i]))

    def isContains(self,str_input,name):
        if str_input==None:
            return False
        if str_input.__len__()==0:
            return False
        ret=True
        for f in self.hashFunc:
            loc=f.hash(str_input)
            ret=ret & self.r.getbit(name,loc)
        return ret

    def insert(self,str_input,name):
        for f in self.hashFunc:
            loc=f.hash(str_input)
            self.r.setbit(name,loc,1)

uid=['alskdjflkasjdf','kajdsklfjlkasdf','lhjkkjhrwqer','alskdjflkasjdf']
bf=BloomFilter()
err_time=0
for id in uid:
    if bf.isContains(id,'test'):
        err_time+=1
    else:
        bf.insert(id,'test')
print(err_time)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值