您的位置:首页 > 运维架构 > Linux

linux-网页抓取(2)

2012-05-16 21:25 190 查看

五、解析网页源代码,得到所需要信息

解析html并不复杂,只是有点麻烦而已。因为页面不可能全部读入内存在解析,只有分开读。分开读就必须要考虑需要查找的标签有可能只读到一部分这种情况。如读1024字节数据,我需要在里面找<div class="article_title">,碰巧的是,1024字节数据最后几位是<div class.在这种情况下,我不能简单的说1024字节里没有我所需要的,那就丢掉这1024字节。这样导致的后果解析出来的文章有遗漏。
需要解析的标签如下:
#define ARTICLE_TITLE ("<div class=\"article_title\">")
#define ARTICLE_MANAGE ("<div class=\"article_manage\">")
#define BLOG_TITLE ("<div class=\"blog_title\">")
#define URL_LINK ("<a href=")
#define LINK_TITLE ("<span class=\"link_title\"><a href=")
#define LINK_TITLE_END ("</a></span>")
#define LINK_VIEW ("<span class=\"link_view\"")
#define LINK_COMMENTS ("<span class=\"link_comments\"")
#define LINK_POSTDATE ("<span class=\"link_postdate\">")
#define BLOG_RANK ("<ul id=\"blog_rank\">")
#define BLOG_STATISTICES (" <ul id=\"blog_statistics\">")
#define URL_END ("</a>")
#define DIV_END ("</div>")
#define SPAN ("<span>")
#define SPAN_END ("</span>")
#define UL_END  ("</ul>")

我的解析流程图如下所示,有待优化。



1、从保存的首页中读1024字节到数组。

2、strcat到2048个字节的数组,多定义一个2048字节的数组,就是为了解决查找标签有可能只读到一部分的情况。

3、判断状态,自定义5个状态

#define TAG_RESOLV_ARTICLE 0  //解析文章标题、URL
#define TAG_RESOLV_ARTICLE_STATIS 1//解析文章访问信息
#define TAG_RESOLV_RANK 2//解析博主博客的访问信息
#define TAG_RESOLV_STATIS 3//解析博主文章统计
#define TAG_RESOLV_END 4//解析结束


4、根据状态查找相应的标签位置。

如果状态为TAG_RESOLV_RANK,则查找<ulid="blog_rank">和</ul>是否在数组中。只有两个标签同时在数组中,才解析标签所包含的有用信息。当<ulid="blog_rank">存在,而</ul>不存在时,则丢掉<ulid="blog_rank">之前的数据,在读1024字节数据后在解析。引用我自己写的一段代码来分析一下。

/*
*功能:解析博客排名,访问量等。
*/
int resolvBlogRank(char *buf, int len, struct BloggerInfo *blogger, int *tag) {
char *blog_rank_start, *blog_rank_end, *span_start, *span_end;
char tmpbuf[BUFFERLEN * 2];
int roll_back_loc,buf_len;
bzero(tmpbuf, sizeof (tmpbuf));
blog_rank_start = strstr(buf, BLOG_RANK);//找到BLOG_RANK第一次出现的位置(呵呵,只会出现一次)
if (blog_rank_start == 0) {//如果buf数组里面没有出现BLOG_RANK,则只保留buf数组最后200个字节。为什么是200?主要是因为BLOG_RANK所包括的字符长度目前不会超过200哈。
buf_len=strlen(buf);
roll_back_loc=buf_len-200>0?buf_len-200:0;
strcat(tmpbuf, buf + roll_back_loc);
bzero(buf, len);
strcat(buf, tmpbuf);
} else {//BLOG_RANK出现在buf里面
blog_rank_end = strstr(blog_rank_start + strlen(BLOG_RANK), UL_END);//找与BLOG_RANK对应的结尾标签,这里是</ul>
if (blog_rank_end == 0) {//UL标签没有找到,则保留BLOG_RANK之后的数据
strcat(tmpbuf, blog_rank_start);
bzero(buf, len);
strcat(buf, tmpbuf);
} else {//UL标签找到
span_start = strstr(blog_rank_start + strlen(BLOG_RANK), SPAN);
span_end = strstr(span_start + strlen(SPAN), SPAN_END);
blogger->visits = myatoi(span_start + strlen(SPAN), span_end);//myatoi函数是我自己写的,用于将字符串转换为整数。如“第10000名”=》10000
span_start = strstr(span_end + strlen(SPAN_END), SPAN);
span_end = strstr(span_start + strlen(SPAN), SPAN_END);
blogger->integral = myatoi(span_start + strlen(SPAN), span_end);
span_start = strstr(span_end + strlen(SPAN_END), SPAN);
span_end = strstr(span_start + strlen(SPAN), SPAN_END);
blogger->ranking = myatoi(span_start + strlen(SPAN), span_end);
*tag = TAG_RESOLV_STATIS;
strcat(tmpbuf, blog_rank_end + strlen(UL_END));
bzero(buf, len);
strcat(buf, tmpbuf);
}
}
return 0;
}


5、循环,直到所解析的内容解析完毕

六、根据解析出来的文章URL,发送HTTP请求,保存返回的网页源代码

我是以文章名作为文件的名字,这里需要注意一个问题,当文件名出现/时,必须把文件名中的/替换为别的符号,我是替换为_符号。因为/在linux中属于路径的一部分。

至此,linux网页抓取工具就宣告完毕。

接下来的工作:

1.网页抓取是单线程的,接下来会采用多线程模式。
2.网页抓取没有抓取图片。js,css,所以在有网络的情况下才能呈现该有的样子。
3.代码很多地方需要优化,有的地方有点乱。
4.准备做个windows版本。不考虑做界面。
5.揉和window版本和linux版本,做个通用版。其实通用版还不是不同操作系统调用不同的函数而已。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: