问题:
在网络爬虫中,有一个要考虑的问题,由于网络间的链接错综复杂,蜘蛛在网络间爬行很可能会形成“环”。为了避免形成“环”,就需要知道蜘蛛已经访问过那些URL。给一个URL,怎样知道蜘蛛是否已经访问过呢?有如下几种方案:
1. 将访问过的URL保存到数据库。
2. 用HashSet将访问过的URL保存起来。那只需接近O(1)的代价就可以查到一个URL是否被访问过了。
3. URL经过MD5或SHA-1等单向哈希后再保存到HashSet或数据库。
4. Bit-Map方法。建立一个BitSet,将每个URL经过一个哈希函数映射到某一位。
方法1~3都是将访问过的URL完整保存,方法4则只标记URL的一个映射位,即是布隆过滤的方法。
在我前面文章中提到过,我实现了一个垂直爬虫,使用的是第 2 种和第 3 种方法的综合。但是效率是不高的,因为对于每一个 url 如果没有在 HashSet 中命中,就要去查询数据库,对于每一个 url 都去查询数据库,效率可想而知。实际上,在爬虫中,我们可以允许一部分 url 不爬取,但是不能允许一个 url 被重复爬取。布隆过滤器刚好算法这种需求,允许有“命中”的误判。
我们定义一个 m 位的unsigned int(或者由多个 unsigned int 组合而成)N,引入 k 个 hash 函数,针对每一个 url ,分别进行 hash,得到 k 个数字 x。将 N 的第 x 位都标记为1。
查询 url 是否已经被处理过,就是要判断 url 的 对应的那些 hash 位是否全为1.如果不全为1,则一定没有处理过,否则很有可能处理过。如图1.