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版本,做个通用版。其实通用版还不是不同操作系统调用不同的函数而已。