分布式爬虫实验设计文档_第1页
分布式爬虫实验设计文档_第2页
分布式爬虫实验设计文档_第3页
分布式爬虫实验设计文档_第4页
分布式爬虫实验设计文档_第5页
已阅读5页,还剩13页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、精选优质文档-倾情为你奉上分布式网络爬虫实验五组 赵成龙、黄莹 一、需求分析随着国际互联网的迅速发展,网上的信息越来越多,全球网页数量超过20亿,每天新增加730万网页。要在如此浩瀚的信息海洋里寻找信息,就像“大海捞针”一样困难。在实际生活中我们经常会使用像百度、Google这些搜索引擎检索各种信息,搜索引擎正是为了解决这个问题而出现的技术,而网络爬虫正是搜索引擎所需要的关键部分既然百度、Google这些搜索引擎巨头已经帮我们抓取了互联网的大部分信息,为什么还要自己写爬虫呢?因为深入整合信息的需求是广泛存在的,在企业中,爬虫抓取下来的信息可以作为数据仓库多维展现的数据源,也可以作为数据挖掘的来

2、源,甚至有人为了炒股,专门抓取股票信息。这些实际问题的解决所需要的根本技术就是分布网络爬虫。本次实验主要的内容就是利用IO复用抓取网页,并多线程的分析每个抓取到的网页所包含的URL信息,通过消息队列将抓取网页的部分和分析网页部分进行通信,最终记录下网页中所包含的所有URL,实现分布式网络爬虫。二、实验架构及原理本实验分为两个模块:爬取网页模块、网页分析模块。实验架构如图2.1所示图2.1 分布是网络爬虫框架爬取网页模块采用socket通信方式实现客户端与服务器的通信:首先将客户端与服务器进行三次握手后建立连接,客户端发送HTTP请求头,服务器端收到客户端请求后,进行HTTP响应,发送相应的网页

3、信息,客户端收到服务器的响应后将所获得网页文件交给网页分析模块进行处理并提取URL。流程图如图所示:图2.2 爬取网页模块流程图网页分析模块主要工作如下图流程图所示。而本模块的网页分析处理主要在于对抓取到的HTML文件的内容进行URL的提取,我们主要运用正则表达式进行字符串的匹配操作。通过采用Regex正则表达式库和Pcre正则表达式库进行了两种尝试,并根据网页的情况设计了测试用例,进行程序的检验。图2.3 网页分析模块流程图三、模块设计及代码实现3.1爬取网页模块设计3.1.1 DNS解析考虑到网页爬取域名转换的问题,需要将URL进行DNS解析。DNS解析是将一一对应的域名与IP地址进行转换

4、的一种技术,域名解析需要由专门的域名解析服务器来完成,整个过程是自动进行的。首先利用接口struct hostent *gethostbyname(const char *name)将需要解析的域名名称作为参数传入到函数中,然后函数执行后返回一个结构体hostent,其中包括了域名所对应的ip地址列表信息。具体代码如下:char* dns_decode(char host) struct hostent* ht=NULL; struct in_addr* tmp; char *dns20; int i=0; if(ht=gethostbyname(host)=NULL) herror(&quo

5、t;gethostbyname wrong!n"); return NULL; else printf("get the host:%sn",host); while(tmp=(struct in_addr*)*ht->h_addr_list) dnsi=(char *)inet_ntoa(*tmp); printf("IP:%sn",dnsi); i+;/ printf("IP:%sn",inet_ntoa(*tmp); ht->h_addr_list+; return dns0;3.1.2 Socket连接S

6、ocket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。下图是socket建立连接的流程图:图3.1 socket建立连接流程图服务器端先初始化Socket,然后与端口绑定(bind),对端口进行监听(listen),调用accept阻塞,等待客户端连接。在这时如果有个客户端初始化一个Socket,然后连接服务器(connect),如果连接成功,这时客户端与服务器端的连接就建立了。客户端发送数据

7、请求,服务器端接收请求并处理请求,然后把回应数据发送给客户端,客户端读取数据,最后关闭连接,一次交互结束。本模块实现的是客户端,首先初始化好网页所在服务器的ip地址及端口号,然后通过int connect(int sockfd, const struct sockaddr* server_addr, socklen_t addrlen)函数连接到服务器端,为之后发送HTTP请求头做准备。具体代码如下:int open_socket(struct in_addr server_ip) int client_sock; struct sockaddr_in server_addr; client_

8、sock=socket(AF_INET,SOCK_STREAM,0); if(client_sock<0) printf("socket errorn"); return -1; bzero(&server_addr,sizeof(server_addr); server_addr.sin_family=AF_INET; / server_addr.sin_addr.s_addr=htonl(server_ip.s_addr); server_addr.sin_addr.s_addr=server_ip.s_addr; server_addr.sin_port

9、=htons(80); if(connect(client_sock,(struct sockaddr*)&server_addr,sizeof(struct sockaddr)=-1) printf("connect error!n"); return -1; printf("open success!n"); return client_sock;3.1.3 发送HTTP请求头并获得相应(1)客户端要向服务器发送一个HTTP请求头,然后服务器根据HTTP请求头的内容响应信息发送回给客户端。请求头内容如下所示:char * head_info=

10、"GET /index.html HTTP/1.1rn","HOST: rn","User-Agent: Mozilla/5.0(X11;Linux i686;rv:24.0)Gecko/ Firefox/24.0rn","Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8rn","Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3rn

11、",/"Accept-Encoding: gzip,deflatern","Connection: keep-alivern","rn",NULL;其中:l Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3客户端支持的语言分别是中文和简体中文,优先支持简体中文。l Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8客户端支持的 MIME 类型分别是 text/html、appli

12、cation/xhtml+xml、application/xml 和 */*,优先顺序是它们从左到右的排列顺序。l Accept-Encoding: gzip, deflate客户端支持的压缩编码是 gzip 和 deflate。l Host: 域名Host表示请求的服务器网址;l Connection: Keep-AliveConnection表示客户端与服务连接类型;Keep-Alive表示持久连接;(2)HTTP响应信息在响应中唯一真正的区别在于第一行中用状态信息代替了请求信息。状态行(status line)通过提供一个状态码来说明所请求的资源情况。最常用的状态码如下:2最常用的状态码

13、有:l 200 (OK): 找到了该资源,并且一切正常。l 304 (NOT MODIFIED): 该资源在上次请求之后没有任何修改。这通常用于浏览器的缓存机制。l 401 (UNAUTHORIZED):客户端无权访问该资源。这通常会使得浏览器要求用户输入用户名和密码,以登录到服务器。l 403 (FORBIDDEN): 客户端未能获得授权。这通常是在401之后输入了不正确的用户名或密码。l 404 (NOT FOUND): 在指定的位置不存在所申请的资源本实验只记录状态码为200 OK的信息。发送HTTP请求到搜狐新闻服务器,服务器返回响应头,实验结果如图所示:图3.2 响应信息3.2网页解

14、析模块设计3.2.1正则表达式的设计考虑到抓取的html文件中标签<a>的链接内容的几种情况,设计了相应的正则表达式,具体如下四种情况:(1)./a/b/c.html类型 正则表达式为:<as*>*hrefs*=s*"./(w*/?)*.html?"s*>(2)./a/b/c.html类型 正则表达式为:<as*>*hrefs*=s*"./(w*/?)*.html?"s*>(3)././a/b/c.html类型 正则表达式为:<as*>*hrefs*=s*"././(w*/?)*.ht

15、ml?"s*>(4)a/b/c.html类型正则表达式为:<as*>*hrefs*=s*"(w*/?)*.html?"s*>然后将上述四种情况综合起来,通过“或”(即“|”)连接组成最终的提取URL的正则表达式如下:<as*>*hrefs*=s*"./(w*/?)*.html?"s*>|<as*>*hrefs*=s*"./(w*/?)*.html?"s*>|<as*>*hrefs*=s*"././(w*/?)*.html?"s*>

16、;|<as*>*hrefs*=s*"(w*/?)*.html?"s*>3.2.2测试用例的设计由于两人分工,在没有得到抓取的html文件内容时,先根据上述不同四种情况设计了测试用例。作为正则表达式的待检测字符串,用来检验程序的正确性,具体如下所示: "<a href="./abc/def/efd.html"> adfaaf134 <a href ="./a/b.html">affdsfasdf <a href="././aff/faf.htm">afd

17、sa <a class="ada" href="acd.html">"3.2.3利用Regex库提取网页URL首先利用了Regex正则表达式库进行URL的字符串匹配。采用接口int regcomp(regex_t *preg, const char *pattern, int cflags) 将要进行匹配的正则表达式进行编译,做匹配前的准备工作。编译后采用int regexec(const regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch,int

18、eflags)用来检测字符串是否匹配正则表达式,具体的相应代码如下:#include<stdio.h>#include<stdlib.h>#include<regex.h>#include<sys/types.h>int main() int i,j,k; char *result30; char *s = "<a href="./abc/def/efd.html"> adfaaf134 <a href ="./a/b.html">affdsfasdf <a href

19、="././aff/faf.htm">afdsa <a class="ada" href="acd.html">" char *pattern = "<as*>*hrefs*=s*"./(w*/?)*.html?"s*>|<as*>*hrefs*=s*"./(w*/?)*.html?"s*>|<as*>*hrefs*=s*"././(w*/?)*.html?"s*>|<as*&g

20、t;*hrefs*=s*"(w*/?)*.html?"s*>" / char *s="456|123" / char *pattern="w+" regex_t regex; int errorNo = regcomp(&regex,pattern,REG_EXTENDED); char *errorMsg = (char*)malloc(sizeof(char)*200); if(errorNo!=0) regerror(errorNo,&regex,errorMsg,200); printf(&qu

21、ot;Error,%s",errorMsg); int offset = 0; regmatch_t pmatch10; /printf("%sn",s); for(j=0;j<4;j+) int status = regexec(&regex,s+offset,10,pmatch,0); / printf("%dn",status); if(status!=0) / printf("over!n"); break; /* else / printf("find: "); */ / prin

22、tf("j:%dn",j); / printf("so:%dn",pmatch0.rm_so); / printf("eo:%dn",pmatch0.rm_eo); / resultj=s+offset; for(i=pmatch0.rm_so,k=0;i<pmatch0.rm_eo&&k<200;i+,k+) resultjk=(s+offset)i; / putchar(s+offset)i); offset+=pmatch0.rm_eo; resultjk='0' printf(&qu

23、ot;%sn",resultj); return 0; 在linux环境下编译并执行上述C程序,并将结果打印如来,如下图所示。图3.3 Regex库匹配结果然而利用Regex库通过多次调试发现只能将整个标签<a>提取出来,但是无法将标签<a>中的href后两个双引号中具体的.hmtl文件获取出来。其实通过正则表达式规范的零宽断言是可以做到的,但是Regex库并不支持零宽断言,即当满足某个条件式时,匹配出后面的字符串。因此选择更符合要求的Pcre库进行匹配提取。3.2.4利用Pcre库提取网页URLPcre是一个很强大的正则库,它是perl语言兼容正则表达式,是

24、一种用C语言写的正则库。利用Pcre库与Regex道理类型,即首先采用pcre *pcre_compile(const char *pattern, int options,const char *errptr, int *erroffset,const unsigned char *tableptr)来编译我们的正则表达式。在进行编译正则表达式时设置了PCRE-DOTALL这个修饰符, 模式中的点号元字符匹配所有字符, 包含换行符。如果没有这个修饰符, 点号是不匹配换行符。这也是考虑到有时候这个标签<a>在html文件中会出现在换行的位置。编译后采用int pcre_exec(c

25、onst pcre *code, const pcre_extra *extra,const char *subject, int length, int startoffset,int options, int *ovector, int ovecsize)来执行正则匹配。其中ovector为匹配成功后所匹配的子串在字符串中的位置,数组中第一位为第一个匹配结果的开始位置,第二个表示结束位置,第三个表示在有子串时第一个子串的开始位置,第四个表示第一个子串的结束位置,然后以此类推。因此要想实现获得href后面双引号的内容,只需要在设计正则表达式是在原有基础上在匹配两个双引号的位置加上小括号(),

26、作为一个子串,然后ovector2和ovector3中的内容就分别是子串的开始和结束的位置,即可获得双引号内.html这样的URL。具体代码如下所示。#include<stdio.h>#include<string.h>#include<pcre.h>#define OVECCOUNT 30int main() pcre *p_compile; const char *error; int erroffset; int ovectorOVECCOUNT=0; / int p_exec,i,j=0,k,offset=0; int p_exec,i,offset

27、=0; / char *result60; / char *src = "abc123def456dsf7890" / char *pattern = "d+" char *src ="<a href="./abc/def/efd.html">afdafas <a href ="./a/b.html">afgsggs <a href="././aff/faf/htm">asdfa dfa<a class ="ada" hre

28、f="acd.htm">" / char *pattern = "<as*>*hrefs*=s*"(./(w*/?)*.html?)"s*>|<as*>*hrefs*=s*"(./(w*/?)*.html?)"s*>" char *pattern = "<as*>*hrefs*=s*"(./(w*/?)*.html?)"s*>|<as*>*hrefs*=s*"(./(w*/?)*.html?)&

29、quot;s*>|<as*>*hrefs*=s*"(././(w*/?)*.html?)"s*>|<as*>*hrefs*=s*"(w/?)*.html?)"s*>" printf("nSubject String:n%sn",src); printf("n"); printf("Pattern:n%sn",pattern); p_compile = pcre_compile(pattern,PCRE_DOTALL,&error,&am

30、p;erroffset,NULL); if(p_compile = NULL) printf("PCRE compilation failed at offset %d: %sn",erroffset,error); return 1; printf("nResult is:n");/for(j=0;j<=2;j+)while(1) p_exec = pcre_exec(p_compile,NULL,src+offset,strlen(src+offset),0,0,ovector,OVECCOUNT); if(p_exec<0&&a

31、mp;(src+offset)offset=0) /* if(p_exec = PCRE_ERROR_NOMATCH) printf("Sorry,no match.n"); else printf("Matching error %dn",p_exec);*/ free(p_compile); break; return 1; / printf("nSuccess,has matched.nn"); for(i=ovector2;i<ovector3;i+) putchar(src+offset)i); / *resultj=(src+offset)i; / resultj+; / resultj='0' / printf("%sn",resultj-(ovector1-ovector0); offset+=ovector1; printf("n");free(p_compile);return 0;在linux环境下编译并执行上述C程序,并将结果打印如来,如下图所示。图3.4 PCRE库匹配结果经过数次调试,结果一直是只匹配出第一种情况

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论