您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 项目/工程管理 > 网络爬虫工具--larbin代码分析(zz)
在larbin里判断用一个URL是否被抓取过,用的是bloomfilter算法(至少网上的人这么说),但是我感觉与《数学之美系列二十一-布隆过滤器(BloomFilter)》中所介绍的算法有着很大的不同,因为larbin中只是简单用了hash方法,它有点像位图法,但我的算法很一般,意见仅供参考。先看一下hashTable的类定义:classhashTable{private:ssize_tsize;char*table;public:/*constructor*/hashTable(boolcreate);/*destructor*/~hashTable();/*savethehashTableinafile*/voidsave();/*testifthisurlisallreadyinthehashtable*returntrueifithasbeenadded*returnfalseifithasallreadybeenseen*/booltest(url*U);/*setaurlaspresentinthehashtable*/voidset(url*U);/*addanewurlinthehashtable*returntrueifithasbeenadded*returnfalseifithasallreadybeenseen*/booltestSet(url*U);};它只有两个成员变量,一个是它的大小,一个是它的内容。Save函数是把hashTable保存到一个文件中,test函数是判断一个url是否已经存在于这个hashtable,set函数是将这个url在hashtable中标明已经见过了,testSet判断这个url有没有被加入过。/*constructor*/hashTable::hashTable(boolcreate){ssize_ttotal=hashSize/8;table=newchar[total];if(create){for(ssize_ti=0;ihashSize/8;i++){table[i]=0;}}else{intfds=open(hashtable.bak,O_RDONLY);if(fds0){cerrCannotfindhashtable.bak,restartfromscratch\n;for(ssize_ti=0;ihashSize/8;i++){table[i]=0;}}else{ssize_tsr=0;while(srtotal){ssize_ttmp=read(fds,table+sr,total-sr);if(tmp=0){cerrCannotreadhashtable.bak:strerror(errno)endl;exit(1);}else{sr+=tmp;}}close(fds);}}}hashSize定义在type.h中,它的大小为64000000,如果是创建一个hashtable,就将table中所有值转置空,否则,去读hashtable.bak中的内容。/*savethehashTableinafile*/voidhashTable::save(){rename(hashtable.bak,hashtable.old);intfds=creat(hashtable.bak,00600);if(fds=0){ecrireBuff(fds,table,hashSize/8);close(fds);}unlink(hashtable.old);}Écrire是法语的write,就是将一个char*的buff写入文件的函数,unlink将文件的连接数减少一个,如果当前文件的连接数目为0,并且没有其他程序打开这个文件,则删除,而remove则将文件直接删除。/*testifthisurlisallreadyinthehashtable*returntrueifithasbeenadded*returnfalseifithasallreadybeenseen*/boolhashTable::test(url*U){unsignedintcode=U-hashCode();unsignedintpos=code/8;unsignedintbits=1(code%8);returntable[pos]&bits;}这里计算得到URL的hashcode,后计算它在哪个字节上,再看它在它个bit上,最后判断这个bit是否已经置过1。/*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;}这里是将hostname和后面部分做hash,nutch里算这个hashcode值的时候,是反过来算的,因为这样同一host的url的hashcode的值就会有更大的差异,是不是会更好些呢?/*setaurlaspresentinthehashtable*/voidhashTable::set(url*U){unsignedintcode=U-hashCode();unsignedintpos=code/8;unsignedintbits=1(code%8);table[pos]|=bits;}这里有test函数差不多,只是最后用或运算置位。在checker.h中声明了两个函数:/**checkifanurlisalreadyknown*ifnotsendit*@paramutheurltocheck*/voidcheck(url*u);/**Checktheextensionofanurl*@returntrueifitmightbeinteresting,falseotherwise*/boolfilter1(char*host,char*file);check的实现如下:voidcheck(url*u){if(global::seen-testSet(u)){hashUrls();//stat//whereshouldthislinkgo?#ifdefSPECIFICSEARCHif(privilegedExts[0]!=NULL&&matchPrivExt(u-getFile())){interestingExtension();global::URLsPriority-put(u);}else{global::URLsDisk-put(u);}#else//notaSPECIFICSEARCHglobal::URLsDisk-put(u);#endif}else{//Thisurlhasalreadybeenseenanswers(urlDup);deleteu;}}Global::seen是一个hashtable对象,用它来判断这个URL是否已经见过。这里SPECIFICSEARCH是判断是我们我们想得到的那种格式,用URLsPriority处理,否则用URLsDisk处理,/**Checktheextensionofanurl*@returntrueifitmightbeinteresting,falseotherwise*/boolfilter1(char*host,char*file){inti=0;if(global::domains!=NULL){boolok=false;while((*global::domains)[i]!=NULL){ok=ok||endWith((*global::domains)[i],host);i++;}if(!ok){returnfalse;}}i=0;intl=strlen(file);if(endWithIgnoreCase(html,file,l)||file[l-1]=='/'||endWithIgnoreCase(htm,file,l)){returntrue;}while(global::forbExt[i]!=NULL){if(endWithIgnoreCase(global::forbExt[i],file,l)){returnfalse;}i++;}returntrue;}Filter1的实现如下:/**Checktheextensionofanurl*@returntrueifitmightbeinteresting,falseotherwise*/boolfilter1(char*host,char*file){inti=0;if(global::domains!=NULL){boolok=false;while((*global::domains)[i]!=NULL){ok=(ok||endWith((*global::domains)[i],host));i++;}if(!ok){returnfalse;}}i=0;intl=strlen(file);if(endWithIgnoreCase(html,file,l)||file[l-1]=='/'||endWithIgnoreCase(htm,file,l)){returntrue;}while(global::forbExt[i]!=NULL){if(endWithIgnoreCase(global::forbExt[i],file,l)){returnfalse;}i++;}returntrue;}前半部分是判断domain是否是配置中提到的,后面是判断这种格式是不是配置中禁止的,html和htm是永真的。配置在larbin.conf中#Doyouwanttolimityoursearchtoaspecificdomain?#ifyes,uncommentthefollowingline#limitToDomain.fr.dk.ukend#Whataretheextensionsyousurelydon'twant#neverforbid.html,.htmandsoon:larbinneedsthemforbiddenExtensions.tar.gz.tgz.zip.Z.rpm.deb.ps.dvi.pdf.png.jpg.jpeg.bmp.smi.tiff.gif.mov.avi.mpeg.mpg.mp3.qt.wav.ram.rm.jar.java.class.diff.doc.xls.ppt.mdb.rtf.exe.pps.so.psdend在main.cc的main函数中刚开始调用了global的构造函数,global函数中有一行是parseFile,它是用于解析配置文件larbin.conf文件的。“UserAgent”:UserAgent“From”:使用者的邮箱“startUrl”:开始爬取的url“waitduration”:访问同一服务器的时间间隔“proxy”:代理服务器信息“pageConnexions”:最大并行连接数“dnsConnexions”:DNS最大并行连接数“httpPort”:用于使用者查看抓取信息的端口“inputPort”:用于向labin添加url等输入信息的telnet端口“depthInSite”:指定爬虫爬取深度“limitToDomain”:限定爬取的域名“forbiddenExtensions”:禁止爬取的扩展名“noExternalLinks”:不爬取和页面不在同一站点的URL其中对startUrl的解析具体如下:elseif(!strcasecmp(tok,startUrl)){tok=nextToken(&posParse);url*u=newurl(tok,global::depthInSite,(url*)NULL);if(
本文标题:网络爬虫工具--larbin代码分析(zz)
链接地址:https://www.777doc.com/doc-4499042 .html