`
mmdev
  • 浏览: 12922387 次
  • 性别: Icon_minigender_1
  • 来自: 大连
文章分类
社区版块
存档分类
最新评论

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

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


前一篇博文《自己动手编写CSDN博客备份工具-blogspider》介绍了blogspider的使用,使用方法很简单,blogspider可以将自己的CSDN博客下载到本地,这里也只提供最基本的功能。这两天有很多哥们儿给我发邮件,想要blogspider的源码,该程序是开源的,有需要的可以留下联系方式。
今天就介绍下blogspider的源代码,其实这里面比较核心的东西就是如何向网站服务器申请我们需要的网页文件。在Java语言,有提供一些网络包,已经将HTTP协议的东西都集成在了包里面,那实现起来就比较简单。最近由于春运期间,大家都在12306网站购票,于是网上就出现了一款抢票的软件,那是用Java写的,是一个谷歌插件。其实那个软件是我一个同事以前的同事写出来的,我们都从这里受益,也买到了回家过年的票,在这里感谢那位牛人。
向Java程序员了解了一下,那个软件的实现原理很简单,步骤如下:
1.访问网站获取网站信息
2.接受到网站服务器的响应消息
3.根据用户选择(硬座,硬卧)的消息再提交到网站服务器
4.得到网站的结果

主要是2个操作:一个是GET方法,一个是POST方法。
GET方法: 从网站服务器下载网页消息,比如网页浏览器可以浏览CSDN网站的新闻与图片,这些都是从网站服务器GET下载到本地;
POST方法:从本地将资料提交到网站服务器,比如在CSDN博客写完文章要点击发表博客,这时候是将一篇文章的所有信息给POST到CSDN服务器。
blogspider的主要目的,就是下载功能,这里使用的是GET方法,用C语言写的都比较低级,这些最基本的都需要自己来实现,等有空看看面向对象编程语言的实现。

废话少说,源码说话:

一.贴出代码中的调试宏,汗,太儿戏了

/*Debug program macro*/
#if 0
#define SPIDER_DEBUG
#endif

二.贴出代码中的一些宏定义,这些涉及到HTML文件的语法,但本代码不需要会html,只需要最基本的字符串处理:

#define BUFSIZE		     1024

#define HTML_ARTICLE     ("<span class=\"link_title\">")
#define HTML_MULPAGE     ("class=\"pagelist\"")
#define BLOG_NEXT_LIST   ("article/list")
#define BLOG_TITLE       ("title=\"")
#define BLOG_HREF        ("<a href=\"")
#define BLOG_DATE        ("<span class=\"link_postdate\">")
#define BLOG_READ        ("<span class=\"link_view\"")
#define BLOG_COMMENT     ("<span class=\"link_comments\"")
#define BLOG_SPAN_HEAD   ("<span>")
#define BLOG_SPAN_END    ("</span>")
#define BLOG_RANK        ("blog_rank")
#define BLOG_LI          ("<li>")
#define BLOG_INDEX       ("index.html")
#define CSDN_BLOG_URL    ("http://blog.csdn.net")
#define CSDN_BLOG_HOST   ("blog.csdn.net")
#define CSDN_BLOG_PORT   (80)

#define BLOG_LOCK        (10)
#define BLOG_UNLOCK      (11)
#define BLOG_DOWNLOAD    (20)
#define BLOG_UNDOWNLOAD  (21)

上面的BLOG_LOCK,BLOG_UNLOCK是爬虫链表的处理锁,这是扩展预留的,现在还没用。本来要用多线程来处理链表,但经过测试,会产生竞争,导致connect超时,这等过完年再试试。

三.这里再给出爬虫链表的结构体与博客存放基本信息的结构体,里面有多一些变量,但没真正的使用,有些只是预留而已:

typedef struct tag_blog_info {
	char *b_url;           /*网址*/
	char *b_host;          /*网站服务器主机名*/
	char *b_page_file;     /*页面文件名称*/
	char *b_local_file;    /*本地保存的文件名称*/
	char *b_title;         /*博客主题*/
	char *b_date;          /*博客发表日期*/
	int   b_port;          /*网址端口号*/
	int   b_sockfd;        /*网络套接字*/
	int   b_reads;         /*阅读次数*/
	int   b_comments;      /*评论次数*/
	int   b_download;      /*下载状态*/
	int   b_lock;          /*处理锁*/
	int   b_seq_num;       /*序号*/
}blog_info;

typedef struct tag_blog_spider {
	blog_info *blog;
	struct tag_blog_spider *next;
}blog_spider;

typedef struct tag_blog_rank {
	int   b_page_total;    /*博客总页数*/
	char *b_title;         /*博客标题*/
	char *b_page_view;     /*博客访问量*/
	char *b_integral;      /*博客积分*/
	char *b_ranking;       /*博客排名*/
	char *b_original;      /*博客原创文章数量*/
	char *b_reship;        /*博客转载文章数量*/
	char *b_translation;   /*博客译文文章数量*/
	char *b_comments;      /*博客评论数量*/
}blog_rank;

四.在一个程序中,使用全局变量不是最好的方法,但都有优缺点:

使用全局变量:
1.优点:操作简单,不用提供太多的函数形参;
2.缺点:不好维护,代码可读性差;所以该程序只使用了3个全局变量。

/*global variable*/
static int g_seq_num = 0;
static char csdn_id[255];
static struct hostent *web_host;

web_host变量用来保存"blog.csdn.net"主机信息,在初始化socket的使用会使用到里面的IP地址, web_host->h_addr_list[0];

五.程序中定义了很多函数,如下:

static char *strrstr(const char *s1, const char *s2);//从s1字符串中查找s2字符串,返回最后一次出现的地址
static char *strfchr(char *s);//过滤掉s字符串中不规则的字符
static int  init_spider(blog_spider **spider);//初始化博客爬虫节点,必须使用指针的指针,否则达不到预期效果
static int  init_rank(blog_rank **rank);//初始化博客存放基本信息的结构体
static void insert_spider(blog_spider *spider_head, blog_spider *spider);//将博客插入爬虫链表
static int  spider_size(blog_spider *spider_head);//计算爬虫链表的长度
static void print_spider(blog_spider *spider_head);//打印爬虫链表,保存到当前目录的*.log文件
static void print_rank(blog_rank *rank);//打印博客基本信息
static void free_spider(blog_spider *spider_head);//释放爬虫链表的空间
static void free_rank(blog_rank *rank);//释放博客基本信息的空间
static int get_blog_info(blog_spider *spider_head, blog_rank *rank);//从博客主页获取博客标题,博客文章的总页数,积分,排名等信息
static int analyse_index(blog_spider *spider_head);分析每一页博客的信息,并添加进爬虫链表
static int download_index(blog_spider *spider_head);//下载博客主页
static int download_blog(blog_spider *spider);//下载每一篇博客
static int get_web_host(const char *hostname);//得到"blog.csdn.net"网站的主机信息
static int connect_web(const blog_spider *spider);//初始化socket,并连接网站服务器
static int send_request(const blog_spider * spider);//给网站服务器发送请求
static int recv_response(const blog_spider * spider);//接受网站服务器的响应消息

六.先给出上述2个字符串处理函数,这家伙,有点罗嗦

/**************************************************************
strrstr  : 查找指定字符串, 返回最后一次出现的地址, 自己实现
***************************************************************/
static char *strrstr(const char *s1, const char *s2)
{
	int len2;
	char *ps1;

	if (!(len2 = strlen(s2))) {
		return (char *)s1;
	}
	
	ps1 = (char *)s1 + strlen(s1) - 1;
	ps1 = ps1 - len2 + 1;

	while (ps1 >= s1) {
		if ((*ps1 == *s2) && (strncmp(ps1, s2, len2) == 0)) {
			return (char *)ps1;
		}
		ps1--;
	}

	return NULL;
}

/*********************************************************
strfchr  : 查找指定字符串中不规则的字符, 并赋空
若没有删除这些不规则的字符,则创建文件的时候将会出错
*********************************************************/
static char *strfchr(char *s)
{
	char *p = s;
	
	while (*p) {
		if (('/' == *p) || ('?' == *p)) {
			*p = 0;
			strcat(s, "xxx");
			
			return p;
		}
		p++;
	}
	
	return NULL;
}

引用星爷的一句话:"功夫其实绝对是适合男女老幼的,打打杀杀只是大家对它的误解。功夫更加是一种艺术,一种不屈的精神。所以,一直以来我都在找方法想将功夫重新包装起来,使得你们这些升斗小民对功夫能够有更深一层的了解。".
轻松一下,继续:

七.初始化爬虫链表,我把很多处理都给独立到函数了,这样可以增加程序的可读性,不能将所有功能都在main函数实现.

/*********************************************************
初始化博客爬虫的链表节点, 申请空间并赋空值
*********************************************************/
static int init_spider(blog_spider * * spider)
{
	*spider = (blog_spider *)malloc(sizeof(blog_spider));
	if (NULL == *spider) {
		#ifdef SPIDER_DEBUG
		fprintf(stderr, "malloc: %s\n", strerror(errno));
		#endif
		return -1;
	}

	(*spider)->blog = (blog_info *)malloc(sizeof(blog_info));
	if (NULL == (*spider)->blog) {
		#ifdef SPIDER_DEBUG
		fprintf(stderr, "malloc: %s\n", strerror(errno));
		#endif
		free(*spider);
		return -1;
	}

	(*spider)->blog->b_url           = NULL;
	(*spider)->blog->b_host          = strdup(CSDN_BLOG_HOST);
	(*spider)->blog->b_page_file     = NULL;
	(*spider)->blog->b_local_file    = NULL;
	(*spider)->blog->b_title         = NULL;
	(*spider)->blog->b_date          = NULL;
	(*spider)->blog->b_port          = CSDN_BLOG_PORT;
	(*spider)->blog->b_sockfd        = 0;
	(*spider)->blog->b_reads         = 0;
	(*spider)->blog->b_comments      = 0;
	(*spider)->blog->b_download      = BLOG_UNDOWNLOAD;
	(*spider)->blog->b_lock          = BLOG_UNLOCK;
	(*spider)->blog->b_seq_num       = 0;
		
	(*spider)->next = NULL;

	return 0;
}

/*********************************************************
初始化博客基本信息结构体,包含以下几个变量:
1.博客页面总页数
2.博客标题
3.博客访问量
4.博客积分
5.博客排名
6.博客原创文章数量
7.博客转载文章数量
8.博客译文文章数量
9.博客评论数量
*********************************************************/
static int init_rank(blog_rank **rank)
{
	*rank = (blog_rank *)malloc(sizeof(blog_rank));
	if (NULL == *rank) {
		#ifdef SPIDER_DEBUG
		fprintf(stderr, "malloc: %s\n", strerror(errno));
		#endif
		return -1;
	}

	(*rank)->b_page_total      = 0;
	(*rank)->b_title           = NULL;
	(*rank)->b_page_view       = NULL;
	(*rank)->b_integral        = NULL;
	(*rank)->b_ranking         = NULL;
	(*rank)->b_original        = NULL;
	(*rank)->b_reship          = NULL;
	(*rank)->b_translation     = NULL;
	(*rank)->b_comments        = NULL;

	return 0;
}

八.爬虫链表的一些处理,这些都比较简单,就都贴出来吧

/*********************************************************
将博客爬虫节点插入爬虫链表
*********************************************************/
static void insert_spider(blog_spider * spider_head, blog_spider * spider)
{
	blog_spider *pspider;

	pspider = spider_head;

	while (pspider->next) {
		pspider = pspider->next;
	}
	
	pspider->next = spider;
}

/*********************************************************
返回爬虫链表长度
*********************************************************/
static int spider_size(blog_spider * spider_head)
{
	int count = 0;
	blog_spider *pspider;

	pspider = spider_head;

	while (pspider->next) {
		pspider = pspider->next;
		count++;
	}
	
	return count;
}

篇幅有点长,待下篇文章...

周星驰:你来这里干什么?
赵薇:我想帮你们比赛。
周星驰:你怎么帮?你快点回火星吧,地球是很危险的。

分享到:
评论

相关推荐

    CSDN博客备份工具-blogspider_v2.0.tar.bz2

    CSDN博客备份工具blogspider,可以备份自己所有的CSDN博客到本地,也可以备份别人的博客。若需要保存别人的技术博客或自己的问题,blogspider可以帮你达到目的。若blogspider程序出现问题,可以关注我的CSDN博客,...

    CSDN博客下载器v2.2

    好消息:CSDN博客下载器v2.0版本增加导出PDF文件功能,方便查看图片与文章。 在无网络环境,也可以看自己的一些文章。当然如果您发现CSDN博客的一些文章值得收藏,你也可以使用本软件轻松的下载到您的电脑。 该版本...

    blogspider

    我的毕业设计,用于抓取百度空间的博客以备份到本地数据库中,可以下载图片到文件系统中。 &lt;br&gt;代码拿出来供大家分享,希望有人一起研究进步。下面是baidu空间所使用数据库的代码,谢谢 create database ...

    csdnBlogSpider:博客备份实用程序

    我们可以使用它来增加csdn id的访问时间,这也是一个博客备份实用程序。 python版本的Blogspider是单线程的,但很简单。 可以与C版本进行比较。 构建csdnBlogSpider 可以在ubuntu 3.11.3上编译和使用...

    node-v12.22.1-linux-x64.tar.xz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    基于微信小程序的校园综合服务小程序

    大学生毕业设计、大学生课程设计作业

    node-v7.8.0-linux-armv7l.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    毕业设计:Python招聘分析系统论文(源码 + 数据库 + 说明文档)

    毕业设计:Python招聘分析系统论文(源码 + 数据库 + 说明文档) 2 需求分析 9 2.1功能需求分析 9 2.2 可行性分析 9 2.2.1 技术可行性 9 2.2.2 经济可行性 9 2.2.3 操作可行性 10 2.2.4 发展可行性 10 2.3系统性需求分析 10 2.4招聘分析系统管理功能 11 3 总体设计 12 3.1 系统结构 12 3.2 数据库设计 12 3.2.1 数据库实体 12 3.2.2 数据库表设计 13 4 运行设计 15 4.1 招聘热门行业分析 15 4.2热门岗位分析界面 15 4.3招聘岗位学历分析界面 16 4.4岗位分布分析界面 16 5 系统测试 18 5.1测试环境与条件 18 5.2功能测试 18 5.3安全测试 18 5.4可用性测试 18 5.5测试结果分析 19

    win11修复-网络正常-永远是地球小图标的bug

    win11修复-网络正常-永远是地球小图标的bug

    node-v7.8.0-linux-armv6l.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    源代码-360通用ASP防护代码(防sql注入).zip

    源代码-360通用ASP防护代码(防sql注入).zip

    node-v10.14.1-win-x86.zip

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    飞行昆虫机器人3D模型

    飞行昆虫机器人

    Excel销售数据可视化文件

    包含切片器可视化大屏、函数动态图表

    毕业设计:python信息加密解密网站的设计与实现(源码 + 数据库 + 说明文档)

    毕业设计:python信息加密解密网站的设计与实现(源码 + 数据库 + 说明文档) 第2章 可行性分析 3 2.1 业务流程图 3 2.2 经济可行性 4 2.3 技术可行性 4 2.4 运行可行性 4 2.5 本章小结 4 第3章 需求分析 5 3.1 信息加密解密系统的发展情况 5 3.2 信息加密解密管理平台的需求分析 5 3.3 数据字典 5 3.4 本章小结 6 第4章 总体设计 7 4.1 系统模块总体设计 7 4.2 数据库设计 9 4.2.1 数据分析 9 4.2.2 数据库的详细设计 10 4.3 本章小结 12 第5章 详细设计与实现 13 5.1 系统运行平台设置 13 5.2 运行环境 13 5.3 开发工具及技术简介 13 5.3.1 开发工具简介 14 5.3.4 技术简介 14 5.4 加密算法技术简介 14 5.5 系统首页设计 15 5.6 系统基本功能设计与实现 15 5.6.1 登录模块设计与实现 15 5.6.2 系统信息展示模块设计与实现 17 5.6.3 信息加密解密的设计与实现 17 5.6.4 用户信息维护模块的设计

    python+pyside6+缝合怪练手程序

    没有意义,纯属练手

    VMware控制台源码

    VMware控制台源码

    9975b93719be3934e351c5ce44c86898.pdf

    9975b93719be3934e351c5ce44c86898.pdf

    node-v7.6.0-linux-armv6l.tar.gz

    Node.js,简称Node,是一个开源且跨平台的JavaScript运行时环境,它允许在浏览器外运行JavaScript代码。Node.js于2009年由Ryan Dahl创立,旨在创建高性能的Web服务器和网络应用程序。它基于Google Chrome的V8 JavaScript引擎,可以在Windows、Linux、Unix、Mac OS X等操作系统上运行。 Node.js的特点之一是事件驱动和非阻塞I/O模型,这使得它非常适合处理大量并发连接,从而在构建实时应用程序如在线游戏、聊天应用以及实时通讯服务时表现卓越。此外,Node.js使用了模块化的架构,通过npm(Node package manager,Node包管理器),社区成员可以共享和复用代码,极大地促进了Node.js生态系统的发展和扩张。 Node.js不仅用于服务器端开发。随着技术的发展,它也被用于构建工具链、开发桌面应用程序、物联网设备等。Node.js能够处理文件系统、操作数据库、处理网络请求等,因此,开发者可以用JavaScript编写全栈应用程序,这一点大大提高了开发效率和便捷性。 在实践中,许多大型企业和组织已经采用Node.js作为其Web应用程序的开发平台,如Netflix、PayPal和Walmart等。它们利用Node.js提高了应用性能,简化了开发流程,并且能更快地响应市场需求。

    人脸识别神经网络,数据集为CelebA,基于Pytorch实现,采用彼此独立的40个卷积神经网络,可识别脸部40个特征

    人脸识别神经网络,数据集为CelebA,基于Pytorch实现 采用彼此独立的40个卷积神经网络,没有共享权重因此算法较慢,可识别脸部40个特征。 包括: 5_o_Clock_Shadow:刚长出的双颊胡须 Arched_Eyebrows:柳叶眉 Attractive:吸引人的 Bags_Under_Eyes:眼袋 Bald:秃头 Bangs:刘海 Big_Lips:大嘴唇 Big_Nose:大鼻子 Black_Hair:黑发 Blond_Hair:金发 Blurry:模糊的 Brown_Hair:棕发 Bushy_Eyebrows:浓眉 Chubby:圆胖的 Double_Chin:双下巴 Eyeglasses:眼镜 Goatee:山羊胡子 Gray_Hair:灰发或白发 Heavy_Makeup:浓妆 High_Cheekbones:高颧骨 Male:男性 Mouth_Slightly_Open:微微张开嘴巴 Mustache:胡子,髭 Narrow_Eyes:细长的眼睛 No_Beard:无胡子 Oval_Face:椭圆形的脸

Global site tag (gtag.js) - Google Analytics