您的位置:首页 > 理论基础 > 计算机网络

网络爬虫URL消重

2015-08-06 20:22 483 查看
在搜索引擎中建立url检测机制,如果一个url被爬取过就记录下来,在爬取新的url之前先和url库中的资源进行对比,如果没有该记录,则正常解析爬取资源,如果有则忽略该url。接下来考虑的就是如何让这个去重的过程更高效的问题。

考虑了如下几个方案:

1 记录爬取过得每一个url,并按顺序存储在数据库中,当爬虫得到新的url之后,先和数据库中已有的url进行对比,如果没有该记录,则进行爬取,爬取成功后把该url追加进数据库中。如果数据库中已有该记录,则忽略该url。这个方案简单直观,问题是如果url数据库很大的话,整个url匹配过程很费时间,如果量不多,可以考虑使用内存数据库,redis之类的带有持久存储功能的数据库。

2 对url进行hash运算映射到某个地址,将该url和hash值当做键值对存放到hash表中,当需要检测新的url的时候,只需要对该url进行hash映射,如果得到的地址在hash表中已经存在,则说明已经被爬取过,则放弃爬取,否则,进行爬取并记录键值对。这样只需要维护一个hash表即可,需要考虑的问题是hash碰撞的问题,互联网上数据如瀚海般,如果hash函数设计不当,碰撞还是很容易发生的。

3 URL采用MD5加密,md5也是采用了基于hash算法,MD5算法能够将任何字符串压缩为128位整数,并映射为物理地址,MD5也是经过时间验证的,MD5进行Hash映射碰撞的几率非常小。我们目前的图片的存储中就用了该方案。

4 采用布隆过滤器,它是一种space efficient的概率型数据结构,用于判断一个元素是否在集合中。在垃圾邮件过滤的黑白名单方法、爬虫(Crawler)的网址判重模块中等等经常被用到。哈希表也能用于判断元素是否在集合中,但是布隆过滤器只需要哈希表的1/8或1/4的空间复杂度就能完成同样的问题。布隆过滤器可以插入元素,但不可以删除已有元素。其中的元素越多,false
positive rate(误报率)越大,但是false negative (漏报)是不可能的。

附布隆过滤器的简单实现:
import java.util.BitSet;

/**

*

* @author 梦里花开

*/

public class BloomFilter {

private static final int DEFAULT_SIZE = 2 << 24;//布隆过滤器的比特长度

private static final int[] seeds = {3,5,7, 11, 13, 31, 37, 61};//这里要选取质数,能很好的降低错误率

private static BitSet bits = new BitSet(DEFAULT_SIZE);

private static SimpleHash[] func = new SimpleHash[seeds.length];

public static void addValue(String value)

{

for(SimpleHash f : func)//将字符串value哈希为8个或多个整数,然后在这些整数的bit上变为1

bits.set(f.hash(value),true);

}

public static void add(String value)

{

if(value != null) addValue(value);

}

public static boolean contains(String value)

{

if(value == null) return false;

boolean ret = true;

for(SimpleHash f : func)//这里其实没必要全部跑完,只要一次ret==false那么就不包含这个字符串

ret = ret && bits.get(f.hash(value));

return ret;

}

public static void main(String[] args) {

String value = "xkeyideal@gmail.com";

for (int i = 0; i < seeds.length; i++) {

func[i] = new SimpleHash(DEFAULT_SIZE, seeds[i]);

}

add(value);

System.out.println(contains(value));

}

}

class SimpleHash {//这玩意相当于C++中的结构体

private int cap;

private int seed;

public SimpleHash(int cap, int seed) {

this.cap = cap;

this.seed = seed;

}

public int hash(String value) {//字符串哈希,选取好的哈希函数很重要

int result = 0;

int len = value.length();

for (int i = 0; i < len; i++) {

result = seed * result + value.charAt(i);

}

return (cap - 1) & result;

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: