分布式爬虫实验设计文档.docx
《分布式爬虫实验设计文档.docx》由会员分享,可在线阅读,更多相关《分布式爬虫实验设计文档.docx(13页珍藏版)》请在冰点文库上搜索。
分布式爬虫实验设计文档
分布式网络爬虫实验
五组赵成龙、黄莹
一、需求分析2
二、实验架构及原理2
三、模块设计及代码实现3
爬取网页模块设计3
<
DNS解析4
Socket连接4
发送HTTP请求头并获得相应6
网页解析模块设计7
正则表达式的设计8
测试用例的设计8
利用Regex库提取网页URL8
利用Pcre库提取网页URL10
》
四、心得体会12
一、需求分析
随着国际互联网的迅速发展,网上的信息越来越多,全球网页数量超过20亿,每天新增加730万网页。
要在如此浩瀚的信息海洋里寻找信息,就像“大海捞针”一样困难。
在实际生活中我们经常会使用像XX、Google这些搜索引擎检索各种信息,搜索引擎正是为了解决这个问题而出现的技术,而网络爬虫正是搜索引擎所需要的关键部分
既然XX、Google这些搜索引擎巨头已经帮我们抓取了互联网的大部分信息,为什么还要自己写爬虫呢因为深入整合信息的需求是广泛存在的,在企业中,爬虫抓取下来的信息可以作为数据仓库多维展现的数据源,也可以作为数据挖掘的来源,甚至有人为了炒股,专门抓取股票信息。
这些实际问题的解决所需要的根本技术就是分布网络爬虫。
本次实验主要的内容就是利用IO复用抓取网页,并多线程的分析每个抓取到的网页所包含的URL信息,通过消息队列将抓取网页的部分和分析网页部分进行通信,最终记录下160000网页中所包含的所有URL,实现分布式网络爬虫。
》
二、实验架构及原理
本实验分为两个模块:
爬取网页模块、网页分析模块。
实验架构如图所示
图分布是网络爬虫框架
爬取网页模块采用socket通信方式实现客户端与服务器的通信:
首先将客户端与服务器进行三次握手后建立连接,客户端发送HTTP请求头,服务器端收到客户端请求后,进行HTTP响应,发送相应的网页信息,客户端收到服务器的响应后将所获得网页文件交给网页分析模块进行处理并提取URL。
流程图如图所示:
图爬取网页模块流程图
网页分析模块主要工作如下图流程图所示。
而本模块的网页分析处理主要在于对抓取到的HTML文件的内容进行URL的提取,我们主要运用正则表达式进行字符串的匹配操作。
通过采用Regex正则表达式库和Pcre正则表达式库进行了两种尝试,并根据网页的情况设计了测试用例,进行程序的检验。
!
图网页分析模块流程图
三、模块设计及代码实现
爬取网页模块设计
DNS解析
考虑到网页爬取域名转换的问题,需要将URL进行DNS解析。
DNS解析是将一一对应的域名与IP地址进行转换的一种技术,域名解析需要由专门的域名解析服务器来完成,整个过程是自动进行的。
首先利用接口structhostent*gethostbyname(constchar*name)将需要解析的域名名称作为参数传入到函数中,然后函数执行后返回一个结构体hostent,其中包括了域名所对应的ip地址列表信息。
具体代码如下:
char*dns_decode(charhost[])
{
?
structhostent*ht=NULL;
structin_addr*tmp;
char*dns[20];
inti=0;
if((ht=gethostbyname(host))==NULL)
{
herror("gethostbynamewrong!
\n");
returnNULL;
~
}
else
{
printf("getthehost:
%s\n",host);
while(tmp=(structin_addr*)*ht->h_addr_list)
{
dns[i]=(char*)inet_ntoa(*tmp);
printf("IP:
%s\n",dns[i]);
(
i++;
a/b/类型
正则表达式为:
]*href\\s*=\\s*\"\\./(\\w*/)*\\.html\"\\s*>
(2)../a/b/类型
正则表达式为:
]*href\\s*=\\s*\"\\.\\./(\\w*/)*\\.html\"\\s*>
(3)./../a/b/类型
正则表达式为:
]*href\\s*=\\s*\"\\./\\.\\./(\\w*/)*\\.html\"\\s*>
(4)a/b/类型
)
正则表达式为:
]*href\\s*=\\s*\"(\\w*/)*\\.html\"\\s*>
然后将上述四种情况综合起来,通过“或”(即“|”)连接组成最终的提取URL的正则表达式如下:
]*href\\s*=\\s*\"\\./(\\w*/)*\\.html\"\\s*>|]*href\\s*=\\s*\"\\.\\./(\\w*/)*\\.html\"\\s*>|]*href\\s*=\\s*\"\\./\\.\\./(\\w*/)*\\.html\"\\s*>|]*href\\s*=\\s*\"(\\w*/)*\\.html\"\\s*>
测试用例的设计
由于两人分工,在没有得到抓取的html文件内容时,先根据上述不同四种情况设计了测试用例。
作为正则表达式的待检测字符串,用来检验程序的正确性,具体如下所示:
"adfaaf134affdsfasdfafdsa";
:
利用Regex库提取网页URL
首先利用了Regex正则表达式库进行URL的字符串匹配。
采用接口intregcomp(regex_t*preg,constchar*pattern,intcflags)将要进行匹配的正则表达式进行编译,做匹配前的准备工作。
编译后采用intregexec(constregex_t*preg,constchar*string,size_tnmatch,regmatch_tpmatch[],inteflags)用来检测字符串是否匹配正则表达式,具体的相应代码如下:
#include<>
#include<>
#include<>
#include
intmain()
<
{
inti,j,k;
char*result[30];
char*s="adfaaf134affdsfasdfafdsa";
char*pattern="]*href\\s*=\\s*\"\\./(\\w*/)*\\.html\"\\s*>|]*href\\s*=\\s*\"\\.\\./(\\w*/)*\\.html\"\\s*>|]*href\\s*=\\s*\"\\./\\.\\./(\\w*/)*\\.html\"\\s*>|]*href\\s*=\\s*\"(\\w*/)*\\.html\"\\s*>";
m_so);
m_eo);
^
m_so,k=0;i{
result[j][k]=(s+offset)[i];
m_eo;
result[j][k]='\0';
printf("%s\n",result[j]);
}
~
return0;
}
在linux环境下编译并执行上述C程序,并将结果打印如来,如下图所示。
图Regex库匹配结果
然而利用Regex库通过多次调试发现只能将整个标签提取出来,但是无法将标签中的href后两个双引号中具体的.hmtl文件获取出来。
其实通过正则表达式规范的零宽断言是可以做到的,但是Regex库并不支持零宽断言,即当满足某个条件式时,匹配出后面的字符串。
因此选择更符合要求的Pcre库进行匹配提取。
/
利用Pcre库提取网页URL
Pcre是一个很强大的正则库,它是perl语言兼容正则表达式,是一种用C语言写的正则库。
利用Pcre库与Regex道理类型,即首先采用pcre*pcre_compile(constchar*pattern,intoptions,constchar**errptr,int*erroffset,constunsignedchar*tableptr)来编译我们的正则表达式。
在进行编译正则表达式时设置了PCRE-DOTALL这个修饰符,模式中的点号元字符匹配所有字符,包含换行符。
如果没有这个修饰符,点号是不匹配换行符。
这也是考虑到有时候这个标签在html文件中会出现在换行的位置。
编译后采用intpcre_exec(constpcre*code,constpcre_extra*extra,constchar*subject,intlength,intstartoffset,intoptions,int*ovector,intovecsize)来执行正则匹配。
其中ovector为匹配成功后所匹配的子串在字符串中的位置,数组中第一位为第一个匹配结果的开始位置,第二个表示结束位置,第三个表示在有子串时第一个子串的开始位置,第四个表示第一个子串的结束位置,然后以此类推。
因此要想实现获得href后面双引号的内容,只需要在设计正则表达式是在原有基础上在匹配两个双引号的位置加上小括号(),作为一个子串,然后ovector[2]和ovector[3]中的内容就分别是子串的开始和结束的位置,即可获得双引号内.html这样的URL。
具体代码如下所示。
#include<>
#include<>
#include<>
#defineOVECCOUNT30
—
intmain()
{
pcre*p_compile;
constchar*error;
interroffset;
intovector[OVECCOUNT]={0};
abc/def/\">afdafasafgsggsasdfadfa";
#
(\\w*/)*\\.html)\"\\s*>|]*href\\s*=\\s*\"(\\.\\./(\\w*/)*\\.html)\"\\s*>";
char*pattern="]*href\\s*=\\s*\"(\\./(\\w*/)*\\.html)\"\\s*>|]*href\\s*=\\s*\"(\\.\\./(\\w*/)*\\.html)\"\\s*>|]*href\\s*=\\s*\"(\\./\\.\\.\\/(\\w*/)*\\.html)\"\\s*>|]*href\\s*=\\s*\"((\\w/)*\\.html)\"\\s*>";
printf("\nSubjectString:
\n%s\n",src);
printf("\n");
printf("Pattern:
\n%s\n",pattern);
》
p_compile=pcre_compile(pattern,PCRE_DOTALL,&error,&erroffset,NULL);
if(p_compile==NULL)
{
printf("PCREcompilationfailedatoffset%d:
%s\n",erroffset,error);
return1;
}
?
printf("\nResultis:
\n");
.\n");
elseprintf("Matchingerror%d\n",p_exec);*/
free(p_compile);
break;
return1;
}
.\n\n");
for(i=ovector[2];i{putchar((src+offset)[i]);
abc/def/,然后就会报出段错误,即Segmentationfault(coredumped),这种问题与其他小组成员讨论分析过,但是都是得不到合理解释,故对于该问题我们目前还尚未解决。
四、心得体会
近6周的实验二,实验过程中遇到了很多问题,也学习了很多知识,收获了很多。
第二次实验的布置课上,听完老师对实验的大致讲解,确实感觉这次实验任务艰巨,需要很多基础知识学习,对网络协议、系统线程、I/O调用都需要熟悉掌握,尤其是对于两个本科非计算机专业的我们,难度显得更大。
但这门课和研究生的价值就在于锻炼自主学习、解决问题的能力。
通过对实验课件、相关基础知识的学习,我们对网络协议、线程管理、I/O调用、Socket通信、Libevent事件驱动、正则表达式都有了清楚的认识。
然后就开始着手设计整个程序框架,并进行各模块的编程。
整个实验刚开始我们组走了一些弯路,网上查到的一些实现思路、具体方法参差不齐,对我们的思路有一定的误导,后来经过与大组内其他同学的请教、讨论我们不断更正设计思路,其实只要是算法原理清晰,代码自然就顺理成章地写了出来。
整个实验有了不小的进展。
实验讨论课上,各组成员展示了自己的思路和进展。
我们从其他组的设计思路、对遇到问题的解决方案中学到了很多东西,整个实验的思路也更深入,自己遇到的一些问题也有了解决的思路。
同时也深深感到和进展快的组之间的差距。
讨论课后,我们加紧调试程序,调试bug是个需要耐心的过程,再加上程序运行一次需要很长的时间,经常一个bug要消耗半天的时间。
调bug过程中,不断摸索出一些小技巧,对程序结构和运行有了更深入的理解,同时也深深体会到一段优美的代码是多么的难得。
第二次实验,让我们来说就是个不小的项目,整个实验过程中,我们对项目结构设计、实现思路、分工都有了较为深入的认识。
对之前停留在课本上的知识有了应用级别的深入认识,编写调试代码的能力也有了很大的提高。
更为关键的是锻炼了,遇到新问题时,自己通过查资料、不断尝试、讨论寻找解决思路并解决问题的能力。
当然,我们还有很多的不足,比如没有流出更多的时间精力对代码和算法进行优化。
同时在分工操作项目的经验上还稍显不足,也希望下次实验能够通过合理分工,锻炼如何两个人更好地推荐一个项目的完成,从而也为后续研究生的科研项目做好经验积累。
总之,从这次实验的感觉上,虽然压力很大,但是正是这压力推进我们前行,提高了自我,也坚定了我们要做好后续的实验,认真修完这门真正有意义和价值的课程!
!