转载--网页去重方法

在爬虫启动工作的过程中,我们不希望同一个网页被多次下载,因为重复下载不仅会浪费CPU机时,还会为搜索引擎系统增加负荷。而想要控制这种重复性下载问题,就要考虑下载所依据的超链接,只要能够控制待下载的URL不重复,基本可以解决同一个网页重复下载的问题。

非常容易想到,在搜索引擎系统中建立一个全局的专门用来检测,是否某一个URL对应的网页文件曾经被下载过的URL存储库,这就是方案。

接着要考虑的就是如何能够更加高效地让爬虫工作,确切地说,让去重工作更加高效。如果实现去重,一定是建立一个URL存储库,并且已经下载完成的URL在进行检测时候,要加载到内存中,在内存中进行检测一定会比直接从磁盘上读取速度快很多。

我们先从最简单的情况说起,然后逐步优化,最终得到一个非常不错的解决方案。

第一,基于磁盘的顺序存储。

这里,就是指把每个已经下载过的URL进行顺序存储。你可以把全部已经下载完成的URL存放到磁盘记事本文件中。每次有一个爬虫线程得到一个任务 URL开始下载之前,通过到磁盘上的该文件中检索,如果没有出现过,则将这个新的URL写入记事本的最后一行,否则就放弃该URL的下载。

这种方式几乎没有人考虑使用了,但是这种检查的思想是非常直观的。试想,如果已经下载了100亿网页,那么对应着100亿个链接,也就是这个检查 URL是否重复的记事本文件就要存储这100亿URL,况且,很多URL字符串的长度也不小,占用存储空间不说,查找效率超级低下,这种方案肯定放弃。

第二,基于Hash算法的存储。

对每一个给定的URL,都是用一个已经建立好的Hash函数,映射到某个物理地址上。当需要进行检测URL是否重复的时候,只需要将这个URL进 行Hash映射,如果得到的地址已经存在,说明已经被下载过,放弃下载,否则,将该URL及其Hash地址作为键值对存放到Hash表中。

这样,URL去重存储库就是要维护一个Hash表,如果Hash函数设计的不好,在进行映射的时候,发生碰撞的几率很大,则再进行碰撞的处理也非常复杂。而且,这里使用的是URL作为键,URL字符串也占用了很大的存储空间。

第三,基于MD5压缩映射的存储。

MD5算法是一种加密算法,同时它也是基于Hash的算法。这样就可以对URL字符串进行压缩,得到一个压缩字符串,同时可以直接得到一个 Hash地址。另外,MD5算法能够将任何字符串压缩为128位整数,并映射为物理地址,而且MD5进行Hash映射碰撞的几率非常小,这点非常好。从另 一个方面来说,非常少的碰撞,对于搜索引擎的爬虫是可以容忍的。况且,在爬虫进行检测的过程中,可以通过记录日志来保存在进行MD5时发生碰撞的URL, 通过单独对该URL进行处理也是可行的。

下面就是是对URL进行压缩的MD5方法,对URL字符串进行压缩:

Java代码   收藏代码
  1. public   static  String md5(String string) {  
  2. char  hexDigits[] = { '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' 'a' 'b' 'c' 'd' ,  
  3. 'e' 'f'  };  
  4. try  {  
  5. byte [] bytes = string.getBytes();  
  6. MessageDigest messageDigest = MessageDigest.getInstance("MD5" );  
  7. messageDigest.update(bytes);  
  8. byte [] updateBytes = messageDigest.digest();  
  9. int  len = updateBytes.length;  
  10. char  myChar[] =  new   char [len *  2 ];  
  11. int  k =  0 ;  
  12. for  ( int  i =  0 ; i < len; i++) {  
  13. byte  byte0 = updateBytes[i];  
  14. myChar[k++] = hexDigits[byte0 >>> 4  &  0x0f ];  
  15. myChar[k++] = hexDigits[byte0 & 0x0f ];  
  16. }  
  17. return   new  String(myChar);  
  18. catch  (Exception e) {  
  19. return   null ;  
  20. }  
  21. }  


在Java中有一个Map类非常好,你可以将压缩后的URL串作为Key,而将Boolean作为Value进行存储,然后将工作中的Map在爬 虫停止工作后序列化到本地磁盘上;当下一次启动新的爬虫任务的时候,再将这个Map反序列化到内存中,供爬虫进行URL去重检测。

第四,基于嵌入式Berkeley DB的存储。

Berkeley DB的特点就是只存储键值对类型数据,这和URL去重有很大关系。去重,可以考虑对某个键,存在一个值,这个值就是那个键的状态。

使用了Berkeley DB,你就不需要考虑进行磁盘IO操作的性能损失了,这个数据库在设计的时候很好地考虑了这些问题,并且该数据库支持高并发,支持记录的顺序存储和随机存储,是一个不错的选择。

URL去重存储库使用Berkeley DB,压缩后的URL字符串作为Key,或者直接使用压缩后的URL字节数组作为Key,对于Value可以使用Boolean,一个字节,或者使用字节数组,实际Value只是一个状态标识,减少Value存储占用存储空间。

第五,基于布隆过滤器(Bloom Filter)的存储。

使用布隆过滤器,设计多个Hash函数,也就是对每个字符串进行映射是经过多个Hash函数进行映射,映射到一个二进制向量上,这种方式充分利用了比特位。

不过,我没有用过这种方式,有机会可以尝试一下。

可以参考Google的

  • http://www.googlechinablog.com/2007/07/bloom-filter.html



转自:

  • http://hi.baidu.com/shirdrn/blog/item/40ed0fb1ceac4d5c0923029d.html

猜你喜欢

转载自itfafa.iteye.com/blog/1584042
今日推荐