最近在用python写小爬虫程序,就是爬去一些自己喜欢图片的,在实现从网页中抓取特定的图片后,发现遗漏了一个问题,那就是怎样忽略已经爬过的网页。多次爬取同一个网页浪费cpu资源,还极有可能陷入死循环中。
在搜索引擎中建立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 (漏报)是不可能的。
布隆过滤器的介绍:http://www.cnblogs.com/allensun/archive/2011/02/16/1956532.html