作者: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_DEBUGfprintf(stderr, "malloc: %s\n", strerror(errno));#endifreturn -1;}(*spider)->blog = (blog_info *)malloc(sizeof(blog_info));if (NULL == (*spider)->blog) {#ifdef SPIDER_DEBUGfprintf(stderr, "malloc: %s\n", strerror(errno));#endiffree(*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_DEBUGfprintf(stderr, "malloc: %s\n", strerror(errno));#endifreturn -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之源码分析(1)相关推荐

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

    作者:gzshun. 原创作品,转载请标明出处! 来源:http://blog.csdn.net/gzshun 周星驰:剪头发不应该看别人怎么剪就发神经跟流行,要配合啊!你看你的发型,完全不配合你的脸 ...

  2. python+shell 备份 CSDN 博客文章,CSDN博客备份工具

    python+shell 备份 CSDN 博客文章,CSDN博客备份工具 在 csdn 写了几年的博客了.多少也积累了两三百篇博文,近日,想把自己的这些文章全部备份下来,于是开始寻找解决方案. 我找到 ...

  3. CSDN 博客备份工具

    前言 核心 登录模块 备份模块 博文扫描模块 演示 如何使用 效果 总结 前言 近段时间以来,听群友博友都在谈论着一件事:"CSDN博客怎么没有备份功能啊?".这其实也在一定程度上 ...

  4. switchyomega规则列表备份_求人不如求己,自己动手写一个CSDN博客备份小工具?...

    前提概要 背景 因为笔者在上个月的时候,突然想扩展一下技术栈,不能仅仅局限于Java,还是得掌握一门工具语言,不然显得太low.所以也就对Python和Golang类的语言有了一些兴趣.也就在上个月简 ...

  5. 【小工具】CSDN博客导出工具-Java集成Maven开发

    CSDN博客导出工具 之前一直想把CSDN的博客导入到自己的网站中,可是由于博客比较多,后面受朋友老郭启发,就找了个时间用Java开发了这款小工具. 转载请注明出处:http://chenhaoxia ...

  6. 博客备份工具——小收集

    打算长期写原创博客了,当然也就要考虑备份问题了.虽然服务器很稳定,但是一旦出什么差错,技术类的东西丢了真的很难恢复,特别痛苦. 所以收集一下可用的工具吧,针对CSDN,因为我们现在有代码片了,不知道各 ...

  7. 博客备份工具BlogDown 软件使用感想

    最近在找博客备份相关的工具,看到了一个不错的博客备份工具BlogDown.使用博客备份BlogDown工具是可以制作博客电子书的.他支持导出多种文件格式,包括常用的电子书格式chm,还有word格式d ...

  8. Blog_Backup:绿色博客备份工具

    Blog_Backup 是一款功能完善的博客备份软件,支持国内所有大型BSP,可导出内容为多种格式.支持的导出的格式包括:RSS 1.0,RSS 2.0,Atom 0.3,单个网页(正序.反序),多个 ...

  9. CSDN博客导出工具

    我把 CSDN 博客当作笔记本来用,记录我遇到的坎儿 突然有一天夜里,我写的博客提交之后都没了,也不知道是哪里出了问题,一般白天博客审查很快,夜里都下班了得等到第二天审查,可是第二天发现博客空了,草稿 ...

  10. 开源-一步步实现cnblogs博客采集工具-对项目需求的分析

    欢迎继续关注CnblogsFan开源项目, 在昨天的项目时间中, 我们已经完成了项目开始前的一些准备工作, 今天, 我们就一起来分析下项目的一些需求. 在对需求进行分析之前我们先来再次熟悉下一个完整项 ...

最新文章

  1. JavaScript中this关键字使用方法详解
  2. 【python图像处理】两幅图像的合成一幅图像(blending two images)
  3. 使用Modernizr探测HTML5/CSS3新特性
  4. 阿里的离职率真的是互联网大厂里最低的吗?
  5. 南开大学java考试试题_2014秋学期南开大学《Java语言程序设计》在线作业附答案...
  6. mybatis mysql selectkey_Mybatis示例之SelectKey的应用
  7. [No0000EB]C# 数组(Array)
  8. 找不到列 dbo 或用户定义的函数或聚合_Power BI 的大数据处理方案:聚合
  9. 浅谈CDN技术的发展历程
  10. linux中的__setup的作用
  11. OneNote的同步问题
  12. JMeter 进行 MD5加密
  13. 核心路由器十项性能指标(转)
  14. 计算机界五位巾帼英雄
  15. 一、highcarts简介
  16. numpy的repeat和pytorch的repeat
  17. 最新界面很漂亮的在线工具箱,包含站长工具箱等等功能
  18. LeetCode力扣刷题——居合斩!二分查找
  19. POP3 SMTP邮件服务器搭建详细图解教程1
  20. libnet编译linux,求助,libnet函数库的应用问题?出现 undefined reference to `libnet_init'错误。...

热门文章

  1. 【SpringBoot系列】最详细demo-- 集成Swagger2
  2. 谷歌命名工具_Google地图正在重命名整个社区
  3. 计算机网络——Cisco Packet Tracer 实验
  4. 跨境电商供应链难点有哪些?
  5. 【历史上的今天】4 月 13 日:Damn Small Linux 首次发布;谷歌关闭短网址服务;数学先驱出生
  6. Data truncation: Data too long for column ‘xxx‘ at row 1
  7. linux上启动eureka集群服务,SpringCloud@Docker系列: 运行Eureka Server集群
  8. 迪赛智慧数——柱状图(多色柱状图):2021年动画电影票房排行榜
  9. oracle远程投毒漏洞复现,oracle TNS Listener远程投毒(CVE-2012-1675)漏洞分析、复现...
  10. 论文阅读——Shadow Attacks:Hiding and Replacing Content in Signed PDFS