布隆过滤器(bloomfilter)在DHT爬虫中的应用

广大网民下载资源的方式还是以BT,磁力链搜索为主,而BT种子的来源就是DHT网络。

 

尝试着写了一个DHT的爬虫, DHT协议中,种子的获取源自两个请求,

1         get_peer,是别的客户端向你请求某个infohash的下载地址

2         announce_peer, 是某个客户端通知你他正在上传/下载某个infohash,他可以作为该infohash的源

 

根据这两个请求的描述,大家也不难看出,采集到的infohash的重复率很高,怎么去保证一个DHT爬虫过滤掉重复的数据呢?

 

一个infohash40个字节的字符串,如0fe6b765f95746aee440fc2552dd59b58c6b5460

Infohash实际是 SHA1算法的出来的一个哈希值,实际是一个20字节的byte序列。某些语言可能不太方便直接用这么一个来做字典的KEY

 

大概估计了一下种子的总数, 20个字节的SHA1,实际上是有 2160次方信息量。数据太大不好评估,而实际的种子数,我只好通过一些成熟的资源网站去统计,如www.btkitty.com有大约 2800万的数据,www.btmay.com也有大几百万的数据。看来数据规模大概是千万级的样子。

 

如果要生成一个1000万条数据的字典,大概需要  40 * 1000 * 10000 字节= 400M 内存。这个大小的内存对于现在的VPS配置来说其实也还好,但是爬虫不可能瞬间爬完所有的数据,为了记录上一次爬了哪些,这400M的字典会定时写一下磁盘。400M写次硬盘就是好几秒钟的事了,如果数据规模比想象中的更大一点,字典到了TB级别的,那就更夸张了。

 

所以这里可以用布隆过滤器,当然也有些其他的措施,但是布隆过滤器在这里是一个很优秀的选择。能够用相对小的内存占用解决去重的问题,但是布隆过滤器也有些缺点。详细的大家可以找下布隆过滤器的说明,网上布隆过滤器大都是概念上的说明,很少有源码的实现。本身也是因为布隆过滤器需要根据具体的环境设计其算法,这里我就直接附上详细的设计思路了。

 

我是将infohash 6hash函数映射到了63字节的小字典里。字典的直接存成了定长的bytearray, 因此内存占用固定为0xFFFFFF/8 * 6 = 12MB理论上能容纳的信息量是2**144。实际用100万的数据做单元测试,出错率为0。所以实际上还能更节省的,比如说少用一个hash算法或者将其中几个hash的长度再减少一点

 

思路清晰了,编码就很简单了,需要实现的接口就是set_flag check_flag save load

//判断是否重复。 6hash算法都是True才是True

def check_flag(s):

    s = s.lower()

    for i in xrange(6):

        n = bloom_filter_func_list[i](s)

        n1 = n >> 3

        n2 = n & 7

        b = bloom_filter_map_list[i]

        if b[n1] & (1 << n2) == 0:

            return False

return True      

 

至于几种hash算法,推荐用djb, dek, 另外infohash本身就是hash算法生成的,直接从里面截取几个字节都是不错的选择,如int(infohash[24:30], 16)


你可能感兴趣的:(爬虫,DHT,布隆过滤器,bloomfilter,infohash)