如何去重?

  • Post category:Python

网络爬虫中的去重是非常重要的一步,它能有效减少爬取重复网页的次数,提高爬取效率和质量。下面,我将为大家讲解网络爬虫如何去重的完整攻略。

一、去重原理

理解去重原理是基础,目前流行的去重方法有哈希去重、布隆过滤器去重和数据库去重等多种。其中,布隆过滤器被认为是最为高效的一种去重方法。

布隆过滤器本质上是一个很长的二进制向量和一些随机映射函数。假如需要对一个网址进行去重,则可以将这个网址通过多个不同的哈希函数映射到二进制向量中。如果向量中每个位置都为1,则说明这个网址已经被访问过了;如果向量中至少存在一个位置为0,则说明这个网址没有被访问过。

二、应用示例

1. Python实现布隆过滤器去重

下面是Python实现布隆过滤器去重的基本代码:

import pyhash
import bitarray

class BloomFilter:
    def __init__(self, size, hash_func):
        self.size = size
        self.hash_func = hash_func
        self.bit_array = bitarray.bitarray(size)
        self.bit_array.setall(0)

    def add(self, item):
        for hf in self.hash_func:
            index = hf(item) % self.size
            self.bit_array[index] = 1

    def contains(self, item):
        for hf in self.hash_func:
            index = hf(item) % self.size
            if self.bit_array[index] == 0:
                return False
        return True

bf = BloomFilter(10000000, [
    pyhash.fnv1_32(),
    pyhash.fnv1a_32(),
    pyhash.metro_64(),
    pyhash.murmur3_32(),
    pyhash.siphash(),
])

urls = ['http://www.baidu.com', 'http://www.google.com', 'http://www.sina.com.cn']
for url in urls:
    if bf.contains(url):
        print('{} is already crawled'.format(url))
    else:
        bf.add(url)
        print('Start crawling for {}'.format(url))

2. Scrapy框架中的去重

Scrapy框架集成了自带的去重功能,默认去重算法是哈希去重。可以通过在settings.py文件中设置DUPEFILTER_CLASS来指定去重算法,包括布隆过滤器去重和数据库去重等。

下面演示如何在Scrapy中使用布隆过滤器去重:

import pyhash
from scrapy.dupefilters import BaseDupeFilter
from scrapy.utils.request import request_fingerprint

class BloomFilterDupeFilter(BaseDupeFilter):
    def __init__(self, key, bit_size=1<<25, num_hashes=5):
        self.key = key
        self.bit_size = bit_size
        self.num_hashes = num_hashes
        self.bloom = BloomFilter(bit_size, [
            pyhash.fnv1_32(),
            pyhash.fnv1a_32(),
            pyhash.metro_64(),
            pyhash.murmur3_32(),
            pyhash.siphash(),
        ])

    @classmethod
    def from_settings(cls, settings):
        key = settings.get('DUPEFILTER_CLASS')
        bit_size = settings.getint('BLOOM_FILTER_BIT_SIZE')
        num_hashes = settings.getint('BLOOM_FILTER_NUM_HASHES')
        return cls(key=key, bit_size=bit_size, num_hashes=num_hashes)

    def request_seen(self, request):
        fp = request_fingerprint(request)
        if self.bloom.contains(fp):
            return True
        else:
            self.bloom.add(fp)
            return False

settings.py文件中的DUPEFILTER_CLASS指定为上述BloomFilterDupeFilter类即可使用布隆过滤器去重。需要注意的是,为了提高去重效率,布隆过滤器中的二进制向量长度请设置到2^25以上。

三、小结

网络爬虫中的去重是非常重要的一步。通过理解去重原理,可以选择最合适的去重方法,并在应用实例中进行实践。在Scrapy框架中,我们可以通过自定义去重器来实现布隆过滤器去重。