自己动手编写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就是了。

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

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值