url去重 亚博电竞 删除抓取工具的网址

日期:2021-01-14 18:13:51 浏览量: 118

URL重复数据删除

为什么在编写搜寻器时需要删除URL重复项?

在搜寻过程中ag百家乐 ,我们不希望多次请求相同的URL地址,因为重复的请求不仅会浪费CPU,还会降低搜寻器的效率银河体育app ,并增加另一方服务器的压力。为了控制重复请求的问题,必须考虑请求所基于的URL。只要不重复下载的URL,就可以基本上解决对同一网页的重复请求的问题。对已爬网的URL进行持久保存并在启动时将其加载到重复数据删除队列中是一个相对强烈的要求。它主要是针对爬网程序无法重新运行而做出的响应,而无需重新请求所有链接URL重复数据删除和策略引入

表面上ag百家乐 ,URL重复数据删除策略是一种消除URL重复的方法。常见的URL重复数据删除策略有五种,如下所示:

# 1.将访问过的ur保存到数据库中
# 2.将访问过的ur保存到set(集合)中,只需要o(1)的代价就可以查询url
#       10000000*2byte*50个字符/1024/1024/1024=9G
# 3.url经过md5等方法哈希后保存到set(或者Redis中)中
# 4. bloomfilter方法对 bitmap进行改进,多重hash函数降低冲突

方法1:将访问的ur保存到数据库中

最简单的实现,但效率最低。

核心思想是将页面上爬网的每个URL存储在数据库中。为了避免重复,有必要在每个存储之前遍历和查询数据库中是否存在当前URL(即,是否已对其进行爬网)。如果存在,请不要保存亚博直播软件ag百家乐 ,否则,请保存当前网址,并继续保存下一个网址,直到结尾。

方法2:将访问的ur保存到设置的存储器中

实现简单,原理与方法1相似。该方法访问方便,基本上不需要查询,但是如果URL过多,将占用大量内存和浪费空间

# 简单计算:假设有1亿条url,每个url平均长度为50个字符,python里unicode编码,每个字符16位,占2
# 个字节(byte)
# 计算式:10^8 x 50个字符 x 2个byte / 1024 / 1024 / 1024 = 9G
#                                    B      M      G
如果是2亿个url,那么占用内存将达18G,也不是特别方便,适合小型爬虫。

方法三.该url由md5和其他方法进行哈希处理url去重,然后保存为set(或Redis)(实现方法如下)

简单计算:一个url经MD5转换,变成一个128bit(位)的字符串,占16byte(字节),方法二中一个url保守估
计占50个字符 x 2 = 100byte(字节),
计算式: 这样一比较,MD5的空间节省率为:(100-16)/100 = 84%(相比于方法二)
(Scrapy框架url去重就是采用的类似方法)
    def request_fingerprint(self, url):
        """Returns a fingerprint for a given url
        Parameters
        ----------
        url : 待请求的url地址
        Returns: str
        """
        #根据url生成指纹
        print('未加密之前:',url)
        md5_obj = hashlib.md5()
        # 进行MD5加密前必须 encode(编码),python里默认是unicode编码,必须转换成utf-8
        # 否则报错:TypeError: Unicode-objects must be encoded before hashing
        md5_obj.update(url.encode(encoding='utf-8'))
        md5_url = md5_obj.hexdigest()
        print('MD5加密后:',md5_url)
        return md5_url

方法4:bloomfilter方法改进了位图,并且多个哈希函数减少了冲突。原理概述

布隆过滤器的原理是,将元素添加到集合中时,该元素通过K个哈希函数映射到位数组中的K中

点并将它们设置为1。检索时,我们只需要查看这些点是否全部为1即可(大约)知道集合中是否存在这些点:如果这些点

如果有0,则检查的元素一定不存在;如果全部为1,则受检查的元素很可能在那里。这是布鲁姆过滤器的基本思想。

在这里插入图片描述

利弊

# 设置散列函数的个数
BLOOMFILTER_HASH_NUMBER = 6
# 布隆过滤器设置bit参数,默认30,占用128M空间,去重量在1亿左右
此参数决定了位数组的位数,如果BLOOMFILTER_BIT为30,则位数组
位2的30次方,这将暂用Redis 128MB的存储空间,url去重数量在1亿左右,
如果爬取的量在10亿,20亿或则更高,则需要将此参数调高
BLOOMFILTER_BIT = 30
class HashMap(object):
    def __init__(self, m, seed):
        self.m = m
        self.seed = seed
    
    def hash(self, value):
        """
        Hash Algorithm
        :param value: Value
        :return: Hash Value
        """
        ret = 0
        for i in range(len(value)):
            ret += self.seed * ret + ord(value[i])
        return (self.m - 1) & ret
class BloomFilter(object):
    def __init__(self, server, key, bit=BLOOMFILTER_BIT, hash_number=BLOOMFILTER_HASH_NUMBER):
        """
        Initialize BloomFilter
        :param server: Redis Server
        :param key: BloomFilter Key
        :param bit: m = 2 ^ bit
        :param hash_number: the number of hash function
        """
        # default to 1 << 30 = 10,7374,1824 = 2^30 = 128MB, max filter 2^30/hash_number = 1,7895,6970 fingerprints
        self.m = 1 << bit
        self.seeds = range(hash_number)
        self.server = server
        self.key = key
        self.maps = [HashMap(self.m, seed) for seed in self.seeds]
    
    def exists(self, value):
        """
        if value exists
        :param value:
        :return:
        """
        if not value:
            return False
        exist = True
        for map in self.maps:
            offset = map.hash(value)
            exist = exist & self.server.getbit(self.key, offset)
        return exist == 1
    
    def insert(self, value):
        """
        add value to bloom
        :param value:
        :return:
        """
        for f in self.maps:
            offset = f.hash(value)
            self.server.setbit(self.key, offset, 1)

按如下所述单独使用

	client = redis.StrictRedis(host='118.24.255.219',port=6380)
    bl = BloomFilter(client,'bl:url')
    url = 'http://www.wanfangdata.com.cn/details/detaype=conference&id=7363410'
    bl.insert(url)
    result = bl.exists(url)
    print(result)
    url1 = 'http://www.wanfangdata.com.cn/details/detaype=conference&id=73634101'
    result = bl.exists(url1)
    print(result)

为了方便使用,我们还可以与scrpay-redis连接。无需重新发明轮子。我们可以直接使用pip3安装ScrapyRedisBloomFilter:

pip3安装scrapy-redis-bloomfilter

# Ensure use this Scheduler(使用自定义的调度器组件)
SCHEDULER = "scrapy_redis_bloomfilter.scheduler.Scheduler"
# Ensure all spiders share same duplicates filter through redis(使用自定义的去重组件)
DUPEFILTER_CLASS = "scrapy_redis_bloomfilter.dupefilter.RFPDupeFilter"
# Redis URL(设置去重指纹需要保存的redis数据库信息)
REDIS_URL = 'redis://:foobared@localhost:6379'
# Number of Hash Functions to use, defaults to 6
#设置散列函数的个数
BLOOMFILTER_HASH_NUMBER = 6
# Redis Memory Bit of Bloomfilter Usage, 30 means 2^30 = 128MB, defaults to 30
# 布隆过滤器设置bit参数,默认30,占用128M空间,去重量在1亿左右
此参数决定了位数组的位数,如果BLOOMFILTER_BIT为30,则位数组
位2的30次方,这将暂用Redis 128MB的存储空间,url去重数量在1亿左右,
如果爬取的量在10亿,20亿或则更高,则需要将此参数调高
BLOOMFILTER_BIT = 30
# Persist
#是否支持断点爬取
SCHEDULER_PERSIST = True

实际上url去重,ScrapyRedisBloomFilter基于scrapy-redis来判断和修改DUPEFILTER重复数据删除组件的重复数据删除部分,如下图所示:

在这里插入图片描述

在这里插入图片描述

学习完此摘要后,您不必再担心url重复了,谢谢阅读。