自己动手编写CSDN博客备份工具-blogspider之源码分析(2)

作者:gzshun. 原创作品,转载请标明出处!
来源:http://blog.csdn.net/gzshun


唐僧:你想要啊?悟空,你要是想要的话你就说话嘛,你不说我怎么知道你想要呢,虽然你很有诚意地看着我,可是你还是要跟我说你想要的。你真的想要吗?那你就拿去吧!你不是真的想要吧?难道你真的想要吗?……
悟空:我Kao!


在开篇,先happy下,有个好心情,才能天天向上,奋发图强,自强不息。

继《自己动手编写CSDN博客备份工具-blogspider》与《自己动手编写CSDN博客备份工具-blogspider之源码分析(1)》博文后,继续贴出处理的一些函数,原理很简单。

一.在博客的下载过程中,打印了一些信息到屏幕,也保存到了*.log文件

/********************************************************* 将爬虫链表的内容打印到log文件,格式为"csdn_id.log",比如 我的博客的地址为: "gzshun.log" *********************************************************/ static void print_spider(blog_spider *spider_head) { char file[BUFSIZE] = {0}; char tmpbuf[BUFSIZE] = {0}; blog_spider *spider; FILE *fp; sprintf(file, "%s.log", csdn_id); fp = fopen(file, "a+"); if (NULL == fp) { #ifdef SPIDER_DEBUG fprintf(stderr, "fopen: %s\n", strerror(errno)); #endif return; } setvbuf(fp, NULL, _IONBF, 0); fseek(fp, 0, SEEK_END); spider = spider_head->next; while (spider) { fprintf(fp, "%d:\n" "%-15s : %s\n" "%-15s : %s\n" "%-15s : %s\n" "%-15s : %d\n" "%-15s : %d\n" "%-15s : %s\n\n", spider->blog->b_seq_num, "title", spider->blog->b_title, "url", spider->blog->b_url, "date", spider->blog->b_date, "reads", spider->blog->b_reads, "comments", spider->blog->b_comments, "download", (spider->blog->b_download == BLOG_DOWNLOAD) ? "Download" : "UnDownload"); spider = spider->next; } fclose(fp); } /********************************************************* 将博客的基本信息打印到标准输出 *********************************************************/ static void print_rank(blog_rank *rank) { char file[BUFSIZE] = {0}; FILE *fp; sprintf(file, "%s.log", csdn_id); fp = fopen(file, "w+"); if (NULL == fp) { #ifdef SPIDER_DEBUG fprintf(stderr, "fopen: %s\n", strerror(errno)); #endif return; } setvbuf(stdout, NULL, _IONBF, 0); fprintf(stdout, "CSDN ID : %s\n" "TITLE : %s\n" "URL : %s/%s\n" "%s\n" "%s\n" "%s\n" "%s\n" "%s\n" "%s\n" "%s\n", csdn_id, rank->b_title, CSDN_BLOG_URL, csdn_id, rank->b_page_view, rank->b_integral, rank->b_ranking, rank->b_original, rank->b_reship, rank->b_translation, rank->b_comments); fprintf(fp, "CSDN ID : %s\n" "TITLE : %s\n" "URL : %s/%s\n" "%s\n" "%s\n" "%s\n" "%s\n" "%s\n" "%s\n" "%s\n", csdn_id, rank->b_title, CSDN_BLOG_URL, csdn_id, rank->b_page_view, rank->b_integral, rank->b_ranking, rank->b_original, rank->b_reship, rank->b_translation, rank->b_comments); fclose(fp); }
唐僧:喂喂喂!大家不要生气,生气会犯了嗔戒的!悟空你也太调皮了,我跟你说过叫你不要乱扔东西,你怎么又…你看我还没说完你又把棍子给扔掉了!月光宝盒是宝物,你把他扔掉会污染花草草也是不对的!

二.申请了空间,在程序结束后必须释放,要不内存泄露了,污染到内存,污染到花花草草也是不对的.

/********************************************************* 释放爬虫链表的空间 *********************************************************/ static void free_spider(blog_spider * spider_head) { blog_spider *pspider; blog_spider *tmp; pspider = spider_head; while (pspider) { if (pspider->blog->b_url) { free(pspider->blog->b_url); } if (pspider->blog->b_host) { free(pspider->blog->b_host); } if (pspider->blog->b_page_file) { free(pspider->blog->b_page_file); } if (pspider->blog->b_local_file) { free(pspider->blog->b_local_file); } if (pspider->blog->b_title) { free(pspider->blog->b_title); } if (pspider->blog->b_date) { free(pspider->blog->b_date); } free(pspider->blog); tmp = pspider->next; /*保存下一个节点地址*/ free(pspider); pspider = tmp; } } /********************************************************* 释放博客基本信息结构体空间 *********************************************************/ static void free_rank(blog_rank *rank) { if (rank->b_title) { free(rank->b_title); } if (rank->b_page_view) { free(rank->b_page_view); } if (rank->b_integral) { free(rank->b_integral); } if (rank->b_ranking) { free(rank->b_ranking); } if (rank->b_original) { free(rank->b_original); } if (rank->b_reship) { free(rank->b_reship); } if (rank->b_translation) { free(rank->b_translation); } if (rank->b_comments) { free(rank->b_comments); } free(rank); }
三.下载个人博客的主页,并分析出必要的信息,比如下载:http://blog.csdn.net/gzshun主页,程序将该文件保存到了本地的"index.html"文件中,先贴出一点html文件的源码,这样就更加清晰的了解代码的字符串解析:

博客标题:

<div class="header"> <div id="blog_title"> <h1> <a href="/gzshun">Open Linux C/C++专栏</a></h1> <h2></h2> <div class="clear"> </div> </div>
博客的总页数:

<!--显示分页--> <div id="papelist" class="pagelist"> <span> 35条数据 共2页</span><strong>1</strong> <a href="/gzshun/article/list/2">2</a> <a href="/gzshun/article/list/2">下一页</a> <a href="/gzshun/article/list/2">尾页</a> 只需要获取到"尾页"前面的数字即可.
博客的排名,积分信息:

<span>gzshun</span> </div> <div id="blog_medal"> </div> <ul id="blog_rank"> <li>访问:<span>54524次</span></li> <li>积分:<span>1070分</span></li> <li>排名:<span>第5615名</span></li> </ul> <ul id="blog_statistics"> <li>原创:<span>29篇</span></li> <li>转载:<span>6篇</span></li> <li>译文:<span>0篇</span></li> <li>评论:<span>209条</span></li> </ul>
贴出源码,这几个字符串解析函数没必要看,自己看下html的规则就能解析出来了:

/********************************************************** 获取博客的基本信息,包括以下几点(以下是按照页面的顺序, 若不按照该顺序,每次查找必须重设偏移量到开头rewind(fp)): 这里获取很多信息, 具体参考blog_spider与blog_rank结构体 **********************************************************/ static int get_blog_info(blog_spider * spider_head, blog_rank * rank) { FILE *fp; int count; char *posA, *posB, *posC, *posD, *posE; char tmpbuf[BUFSIZE] = {0}; char tmpbuf2[BUFSIZE] = {0}; char line[BUFSIZE] = {0}; char *rank_info_addr[7]; fp = fopen(spider_head->blog->b_local_file, "r"); if (NULL == fp) { fprintf(stderr, "fopen: %s\n", strerror(errno)); return -1; } /*查找博客的标题*/ sprintf(tmpbuf, "<a href=\"/%s\">", csdn_id); while (fgets(line, sizeof(line), fp)) { posA = strstr(line, tmpbuf); if (posA) { posA += strlen(tmpbuf); posB = strstr(posA, "</a>"); *posB = 0; /*设置爬虫头结点的标题*/ spider_head->blog->b_title = strdup(posA); rank->b_title = strdup(posA); #ifdef SPIDER_DEBUG printf("%s\n", spider_head->blog->b_title); #endif break; } } /*查找博客文章的总页数*/ while (fgets(line, sizeof(line), fp)) { posA = strstr(line, HTML_MULPAGE); if (posA) { fgets(line, sizeof(line), fp); posB = strrstr(line, BLOG_HREF); /* /gzshun/article/list/N, N就是总页数 */ memset(tmpbuf, 0, sizeof(tmpbuf)); sprintf(tmpbuf, "/%s/%s/", csdn_id, BLOG_NEXT_LIST); posB += strlen(BLOG_HREF) + strlen(tmpbuf); posC = strchr(posB, '"'); *posC = 0; rank->b_page_total = atoi(posB); spider_head->blog->b_seq_num = rank->b_page_total; #ifdef SPIDER_DEBUG printf("b_page_total = %d\n", rank->b_page_total); #endif break; } } /*总共有7条信息: 访问 积分 排名 原创 转载 译文 评论*/ while (fgets(line, sizeof(line), fp)) { posA = strstr(line, BLOG_RANK); if (posA) { count = 0; while (fgets(line, sizeof(line), fp)) { posB = strstr(line, BLOG_LI); if (posB) { if (7 == count) { break; } posB += strlen(BLOG_LI); posC = strstr(posB, BLOG_SPAN_HEAD); posD = posC + strlen(BLOG_SPAN_HEAD); posE = strstr(posD, BLOG_SPAN_END); *posC = 0; *posE = 0; memset(tmpbuf, 0, sizeof(tmpbuf)); memset(tmpbuf2, 0, sizeof(tmpbuf2)); strcpy(tmpbuf, posB); strcpy(tmpbuf2, posD); strcat(tmpbuf, tmpbuf2); rank_info_addr[count++] = strdup(tmpbuf); } } rank->b_page_view = rank_info_addr[0]; rank->b_integral = rank_info_addr[1]; rank->b_ranking = rank_info_addr[2]; rank->b_original = rank_info_addr[3]; rank->b_reship = rank_info_addr[4]; rank->b_translation = rank_info_addr[5]; rank->b_comments = rank_info_addr[6]; break; } } fclose(fp); return 0; }
以上使用了rank_info_addr数组,是为了在while (fgets(line, sizeof(line), fp)) 循环里面方便赋值。
博客里面可能有很多页,必须我的博客就有2页,这时候网址是这样:
http://blog.csdn.net/gzshun/article/list/1
http://blog.csdn.net/gzshun/article/list/2

所以循环下载blog.csdn.net对应自己的博客列表就行,网页文件的名称如:/gzshun/article/list/1 把gzshun改为自己的csdn的id就是了。

先来杯咖啡,待下一篇文章,前几天奔波在火车上,辛苦啊,今天及时赶到,马上发表,持之以恒。。

阅读更多
换一批

没有更多推荐了,返回首页