LabinOpenSpider天网三款爬虫对比分析.docx
- 文档编号:18535391
- 上传时间:2023-08-19
- 格式:DOCX
- 页数:19
- 大小:289.22KB
LabinOpenSpider天网三款爬虫对比分析.docx
《LabinOpenSpider天网三款爬虫对比分析.docx》由会员分享,可在线阅读,更多相关《LabinOpenSpider天网三款爬虫对比分析.docx(19页珍藏版)》请在冰点文库上搜索。
LabinOpenSpider天网三款爬虫对比分析
Labin、OpenSpider、天网三款爬虫对比分析
分类:
搜索引擎2009-11-2111:
57794人阅读评论(5)收藏举报
Labin、OpenSpider、天网是三款比较著名的网络爬虫,其中天网现在已经做成了分布式爬虫,据称天网在ftp搜索方面水平比较高。
这三款爬虫本人都接触过,对于Labin和天网的源代码也研究过一段时间。
、
Larbin:
首先,Labin采用的socket方式是单线程非阻塞式的爬取。
具体的技术实现采用linux/unix的poll轮询接口。
当Larbin读取种子网站以后,会解析出网页中的url.从源代码中来看,Larbin提取url的技术水平并不高,只是采取简单的字符串操作。
然而url是各种各样的,字符串操作能否提取90%以上html网页中的url,还值得怀疑。
当被urls被提取以后,Labin建立了四个队列存取之:
两个优先权队列、两个普通队列。
为什么要这么做呢?
我想做着可能这样想:
优先权队列用作采集优先权高的url,而这个优先权怎么计算?
这个要根据系统的实际情况了!
如果是垂直搜索引擎,可能会根据倾向性、内容相关性来打分,分数高则优先级高。
甚至会用分类、聚类或者各种评判手段,甚至pagerank/hits算法来预先计算url的权重。
如果是普通搜索引擎,那么可以这样计算打分:
要不根据爬取的网页深度,要不根据是否location字段等等。
Larbin中优先权是根据什么来计算的,我想读了上面的东西已经不重要了。
既然提取了urls,就要对url进行域名解析。
Larbin自建立了一个DNS服务器。
关于DNS服务器的运作,鲜有说明。
我自己是这样认为的:
首先,本地(Larbin)的dns与外网的DNS进行交互,将外网的DNS的相关内容读取进来。
然后,就可以响应larbin的解析请求了。
所以当开启DNS服务器的时候,应该会有一个大量读取外网DNS内容的过程。
Larbin似乎是将解析完毕的DNS存入一个管道之中,一头进,一头出。
出的一头就是继续重复爬取了。
另外Larbin的url消重算法是采用的是普通的bloomfilter算法。
不在累赘了。
总结:
从上面看来,Larbin只是一个小型架构的爬虫,并不适合大型分布式爬取。
其架构针对小型爬虫来说,轻装上阵,非常合理。
但是对于大型爬虫则是非常的不合理了。
OpenSpider:
OpenSpider我并没细看,大体上也就是那么个流程。
不过值得一提的是,OpenSpider提取urls采用的是正则表达式的方法。
这个是值得大书特书的。
关于正则表达式的具体设计,需要丰富的工程项目经验。
其设计非常复杂。
天网:
天网的初期版本在这三个爬虫之中是最差劲的。
几乎毫无架构可言。
不过凡事都是从低级做起,还是要大书一番。
勇气可嘉么。
看得出来,天网模仿了很多开源系统。
譬如一个http的简单读取器,还有Larbin似乎也看到了模仿的影子。
低等科技国家只能够从模仿开始。
一味鼓吹创新只能是自欺欺人。
天网开了几个线程,并行进行爬取。
爬取流程大约如下:
足见,天网将爬来的并解析的url直接放在了map,vector等容器中,消重也是简单的MD5匹配。
同时也设置了一个已爬取的容器。
socket采用的是非阻塞的select。
但是我怀疑他们的select没有起作用。
用法等于没有用。
以上是我对三款爬虫的简要分析。
因为没有必要进行非常细致的抠,所以很多地方都是一笔带过。
谬误之处肯定很多的,希望大家多指教。
larbin中的队列结构(2008-08-0511:
53)
分类:
搜索引擎研究
以前整理过的关于larbin的队列结构给需要的网友:
为什么disk和priority的队列都是成对出现的,是因为可以认为每个site在namedSiteList当中都有一个小的队列来保存它的url,这个url的个数是有个限制的,当超过这个限制的时候就不能再把该site下的url放入,但也不能丢弃,而是放入wait队列。
larbin会控制一段时间在disk队列中取url,一段时间在diskWait当中取url。
disk和priority的区别只是优先级的区别。
namedSiteLIst的作用可以任务是实现了DNS缓存;IPSiteList是控制了polite访问。
搜索引擎Larbin设计原理(2006-06-2710:
32)
分类:
搜索引擎研究
搜索引擎Larbin设计原理
第一次看到这篇文章是在卢亮的blog里......
互联网是一个庞大的非结构化的数据库,将数据有效的检索并组织呈现出来有着巨大的应用前景,尤其是类似RSS的以XML为基础的结构化的数据越来越多,内容的组织方式越来越灵活,检索组织并呈现会有着越来越广泛的应用范围,同时在时效性和可读性上也会有越来越高的要求。
这一切的基础是爬虫,信息的来源入口。
一个高效,灵活可扩展的爬虫对以上应用都有着无可替代的重要意义。
要设计一个爬虫,首先需要考虑的效率。
对于网络而言,基于TCP/IP的通信编程有几种方法。
第一种是单线程阻塞,这是最简单也最容易实现的一种,一个例子:
在Shell中通过curl,pcregrep等一系统命令可以直接实现一个简单的爬虫,但同时它的效率问题也显而易见:
由于是阻塞方式读取,dns解析,建立连接,写入请求,读取结果这些步骤上都会产生时间的延迟,从而无法有效的利用服务器的全部资源。
第二种是多线程阻塞。
建立多个阻塞的线程,分别请求不同的url。
相对于第一种方法,它可以更有效的利用机器的资源,特别是网络资源,因为无数线程在同时工作,所以网络会比较充分的利用,但同时对机器CPU资源的消耗也是比较大,在用户级多线程间的频繁切换对于性能的影响已经值得我们考虑。
第三种是单线程非阻塞。
这是目前使用的比较多的一种做法,无论在client还是server都有着广泛的应用。
在一个线程内打开多个非阻塞的连接,通过poll/epoll/select对连接状态进行判断,在第一时间响应请求,不但充分利用了网络资源,同时也将本机CPU资源的消耗降至最低。
这种方法需要对dns请求,连接,读写操作都采用异步非阻塞操作,其中第一种比较复杂,可以采用adns作为解决方案,后面三个操作相对简单可以直接在程序内实现。
效率问题解决后就需要考虑具体的设计问题了。
url肯定需要一个单独的类进行处理,包括显示,分析url,得到主机,端口,文件数据。
然后需要对url进行排重,需要一个比较大的urlHash表。
如果还要对网页内容进行排重,则还需要一个DocumentHash表。
爬过的url需要记录下来,由于量比较大,我们将它写到磁盘上,所以还需要一个FIFO的类(记作urlsDisk)。
现在需要爬的url同样需要一个FIFO类来处理,重新开始时,url会从定时从爬过的urlFIFO里取出来,写到这个FIFO里。
正在运行的爬虫需要从这个FIFO里读数据出来,加入到主机类的url列表里。
当然,也会从前一个FIFO里直接读url出来,不过优先级应该比这个里面出来的url低,毕竟是已经爬过的。
爬虫一般是对多个网站进行爬取,但在同一站点内dns的请求可以只做一次,这就需要将主机名独立于url,单独有一个类进行处理。
主机名解析完成后需要有一个解析完成的IP类与之应用,用于connect的时候使用。
HTML文档的解析类也要有一个,用来分析网页,取出里面的url,加入到urlsDisk。
再加上一些字符串,调度类,一个简单的爬虫基本上就完成了。
以上基本上是Larbin的设计思路,Larbin在具体实现上还有一些特殊的处理,例如带了一个webserver,以及对特殊文件的处理。
Larbin有一点设计不不太好,就是慢的访问会越来越多,占用大量的连接,需要改进,另外如果对于大规模的爬虫,这仅仅实现了抓取的部分,要分布式的扩展还需要增加url的集中管理与调度以及前台spider的分布式算法。
说的简单易懂一些,网络爬虫跟你使用的〖离线阅读〗工具差不多。
说离线,其实还是要跟网络联结,否则怎么抓东西下来?
那么不同的地方在哪里?
1】网络爬虫高度可配置性。
2】网络爬虫可以解析抓到的网页里的链接
3】网络爬虫有简单的存储配置
4】网络爬虫拥有智能的根据网页更新分析功能
5】网络爬虫的效率相当的高
那么依据特征,其实也就是要求了,如何设计爬虫呢?
要注意哪些步骤呢?
1】url的遍历和纪录
这点larbin做得非常的好,其实对于url的遍历是很简单的,例如:
cat[whatyougot]|tr"\n|gawk'{print$2}'|pcregrep^http:
//
就可以得到一个所由的url列表
2】多进程VS多线程
各有优点了,现在一台普通的PC例如一天可以轻松爬下5个G的数据。
大约20万网页。
3】时间更新控制
最傻的做法是没有时间更新权重,一通的爬,回头再一通的爬。
通常在下一次爬的的数据要跟上一次进行比较,如果连续5次都没有变化,那么将爬这个网页的时间间隔扩大1倍。
如果一个网页在连续5次爬取的时候都有更新,那么将设置的爬取时间缩短为原来的1/2。
注意,效率是取胜的关键之一。
4】爬的深度是多少呢?
看情况了。
如果你比较牛,有几万台服务器做网络爬虫,我劝您跳过这一点。
如果你同我一样只有一台服务器做网络爬虫,那么这样一个统计您应该知道:
网页深度:
网页个数:
网页重要程度
0:
1:
:
10
1:
20:
:
8
2:
:
600:
:
5
3:
:
2000:
:
2
4above:
6000:
一般无法计算
好了,爬到三级就差不多了,再深入一是数据量扩大了3/4倍,二是重要度确下降了许多,这叫做“种下的是龙种,收获的是跳蚤。
”
5】爬虫一般不直接爬对方的网页,一般是通过一个Proxy出去,这个proxy有缓解压力的功能,因为当对方的网页没有更新的时候,只要拿到header的tag就可以了,没有必要全部传输一次了,可以大大节约网络带宽。
apachewebserver里面纪录的304一般就是被cache的了。
6】请有空的时候照看一下robots.txt
7】存储结构。
这个人人见智,google用gfs系统,如果你有7/8台服务器,我劝你用NFS系统,要是你有70/80个服务器的话我建议你用afs系统,要是你只有一台服务器,那么随便。
给一个代码片断,是我写的新闻搜索引擎是如何进行数据存储的:
NAME=`echo$URL|perl-p-e's/([^w-.@])/$1eq""?
"":
sprintf("%%%2.2x",ord($1))/eg'`
mkdir-p$AUTHOR
newscrawl.pl$URL--user-agent="+(+)"-outfile=$AUTHOR/$NAME
这一回介绍Larin中的基本数据结构,其实这一部分对于每一个高水平的程序来说,都是相似的,但是在此还是废话一下。
首先从我接触到的第一个数据结构开始(因为我在详细阅读代码前首先做了些源代码修改工作)——Vector
(1)%LARBIN_HOME%/src/utils/Vector
这个类唯一值得一提的就是他的存储空间优化机制。
这在大量的数据结构中都有。
它有两个成员变量:
uintpos;
uintsize;
其中pos代表vector的使用容量,size代表vector的占用容量。
当占用容量不够用,vector就需要进行一次扩容。
代码中是扩1倍容量,如果还不够,就扩到当前需要的量。
vector的使用处:
大家应该还记得第2部分中,用户可以参与的程序部分。
也就是loaded()函数,他的参数是一个html。
它里面包含一个vector用于存储当前页面指向的链接。
如果需要输出特定的链接关系(用于PR)的话,那么就需要用到这个结构。
(2)%LARBIN_HOME%/src/utils/url
这个类主要处理url相关的一些基本问题。
他的成员变量中包含Host,port等url的基础组成部分。
它的内部包含两个hashcode的算法,一个是求对整体url的hash值,一个是对Host求hash值。
这两个求值用在的地方也不太一样。
在后面会详细介绍。
(3)%LARBIN_HOME%/src/utils/Fifo
这个类就是模拟一个队列,当然,在他里面也包含了扩容的算法。
按需扩容的思想在整个程序中有很好地体现。
具体的队列算法想来十分简单了。
这个类还有两个相关的类:
syncFIfo和PersistentFifo,前者支持同步,后者支持同步和备份(文件存储),在具体的使用中再看他们的用途。
(4)%LARBIN_HOME%/src/utils/NameSite
这个类是一个比较重要的类,这个爬虫爬行过程的一些核心代码就在这里面。
首先,它是一组站点的集合,他的成员变量分为两个部分:
网址部分:
charname[maxSiteSize]
uint16port
队列部分:
uint16nburl
url*fifo[maxUrlsBySite]
uint8inFifo
uint8outFifo
在队列中会保存一定量的url,当某个url需要被处理时,则将这个url取出,保存在网址部分的变量中。
在这个类的函数中,还包含一些DNS解析的功能,这些在流程分析中再谈。
(5)%LARBIN_HOME%/src/utils/IPSite
这个类和上面的类类似,不过他保存的就已经是IP地址了。
这个类的结构略显简单,它里面也是包含一个fifo,在这个类中包含了一个功能函数,就是fetch,其实这个函数只是对待访问站点进行连接,并不做真正的内容读取。
还有一些类,比如string,text,hashTable,hashDup就不做介绍了,因为这些类的内容比较少,大家一看名字便知他的含义。
下一次将对Larbin的实现细节做一些分析。
Larbin学习小结
分类:
larbin2011-11-3014:
24432人阅读评论(0)收藏举报
Larbin是一个用C++开发的开源网络爬虫,有一定的定制选项和较高的网页抓取速度。
下图表示了一般爬虫抓取网页的基本过程。
抓取以/Larbin.conf中的startUrl做为种子URLs开始。
下面先来看用于处理url的类:
上面的类图只显示了url类可见的接口。
除了基本的构造函数和私有变量的get函数,url类比较重要的函数是hashCode(),其实现为:
/*returnahashcodeforthisurl*/
uinturl:
:
hashCode(){
unsignedinth=port;
unsignedinti=0;
while(host[i]!
=0){
h=31*h+host[i];
i++;
}
i=0;
while(file[i]!
=0){
h=31*h+file[i];
i++;
}
returnh%hashSize;
}
在全局变量Globle.h中,hashTable*seen用来表示抓取中出现过的URLs。
按照Larbin的默认值hashSize为64,000,000,*seen是一个大小为8,000,000的char数组的hashTable结构,该char数组*table的每一个bit位可以代表一个出现过的URL。
这里使用的是一种叫做BloomFilter的空间效率很高的随机数据结构。
它利用位数组很简洁地表示一个集合,并能判断一个元素是否属于这个集合。
BloomFilter的这种高效是有一定代价的:
在判断一个元素是否属于某个集合时,有可能会把不属于这个集合的元素误认为属于这个集合(falsepositive)。
因此,BloomFilter不适合那些“零错误”的应用场合。
而在能容忍低错误率的应用场合下,BloomFilter通过极少的错误换取了存储空间的极大节省。
(关于BloomFilter的介绍参考了BloomFilter概念和原理和从哈希存储到BloomFilter。
)
设定*table数组bit位的函数实现如下:
/*addanewurlinthehashtable
*returntrueifithasbeenadded
*returnfalseifithasalreadybeenseen*/
boolhashTable:
:
testSet(url*U){
unsignedintcode=U->hashCode();
unsignedintpos=code/8;//该URL的hashCode在table中的索引
unsignedintbits=1<<(code%8);//该hashCode在字节中的bit位
intres=table[pos]&bits;//判断对应bit位是否为1,为1时res为正数
table[pos]|=bits;//将对应bit位标记为1
return!
res;
}
这里只使用了一个hash函数将URL映射到*table中的相应位。
按照BloomFilter的元素判断方法,当对应bit位为1时,表示该URL已经见过。
对于网页内容的简单去重使用的是hashDup*hDuplicate,hashDup这一结构同样基于BloomFilter,其相关实现为:
/*setapageinthehashtable
*returnfalseifitwasalreadythere
*returntrueifitwasnot(ieitisnew)*/
boolhashDup:
:
testSet(char*doc){
unsignedintcode=0;
charc;
for(uinti=0;(c=doc[i])!
=0;i++){
if(c>'A'&&c<'z')
code=(code*23+c)%size;
}
unsignedintpos=code/8;
unsignedintbits=1<<(code%8);
intres=table[pos]&bits;
table[pos]|=bits;
return!
res;
}
显然这里的网页内容去重过于简单,只能区分指向页面内容完全相同的不同链接。
为了分析和处理抓取回的网页和robot文件,Larbin中设计了file类,html类和robots类继承了file类。
下面的类图显示了这几类的关系和相关函数。
html类中的inputHeaders()函数用于处理获得的网页文件的头部,包括链接、状态等。
endInput函数调用其他私有函数进行一系列关于网页内容的分析和链接的提取管理操作。
endInput先调用global:
:
hDuplicate->testSet()检测网页是否重复,再调用parseHtml()进行网页内容的分析。
parseHtml()中比较重要的是调用parseTag()分析html标签,然后调用parseContent(action)针对标签内容进行URL的处理。
parseContent(action)中调用了manageUrl()函数,manageUrl()调用/fetch/checker.cc中的check()函数将URL的加入前端队列。
这些函数之间的调用关系可以在阅读源码时看到。
此外,处理网页的模块还会用到一些文本操作函数,它们定义在/utils/text.h中,当然也需要url类中的相关处理函数。
接下来考虑larbin的URL队列管理。
*global:
:
URLsPriority和*global:
:
URLsPriorityWait是用于特定类型文件下载时所需的队列,这里暂不考虑。
Larbin用于一般爬取时主要用到的队列包括:
PersistentFifo*URLsDisk;//作为URL集合的前段队列,加入新的URL
PersistentFifo*URLsDiskWait;//提供对一定数量的前段URL的非阻塞访问,
//即当队列为空时不阻塞,而直接返回NULL
NamedSite*namedSiteList;//使用URL的hashCode为索引的已访问站点的大表,//维护各个站点的dns属性、对应站点待抓取URL队列
Fifo
Fifo
NamedSite*namedSiteList是维护URL队列的重要数据结构。
在larbin的默认设置中,它可以维护20000个站点的待抓取队列。
NamedSite类的类图如下:
可以看出,NamedSite对每个站点维护着一个fifo队列。
根据不同站点的dns状态,它使用newQuery()通过adns库建立新的dns异步解析服务(DNS服务模块使用了开源的adns库,http:
//www.chiark.greenend.org.uk/~ian/adns),同时可以通过putUrl()和putUrlWait()来管理URL后端队列global:
:
*okSites的URL添加。
至此,本文最开始的第一张爬虫结构图中的主要模块及实现均做了介绍。
整合在一起如下图所示:
Larbin的运行过程可以描述如下:
种子URL文件最初初始化*URLsDisk,读取到namedSiteList中,通过adns库调用,逐渐往Fifo
然后通过html类的方法从下载到的网页中析取出新的URL,新加入前端队列的URL要求符合robotsfilter,并通过hash表对URL去重。
一次抓取结束后进行相关的读写操作,然后通过poll函数选择适合的套接字接口,开始新的抓取。
这样抓取就可以一直循环下去,直到用户终止或者发生中断。
Larbin更详细的实现和定制细节可参考源码注释。
参考资料:
1,搜索引擎Larbin设计原理,
2,Larbin中的队列结构,h
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- LabinOpenSpider 天网 爬虫 对比 分析