一般来说linux下比较大型的程序都是以配置文件作为参数介质传递的,该爬虫也采用配置文件的方式来获取参数,配置文件格式大致如下:

max_job_num=1
#seeds=https://www.baidu.com
#seeds=http://bbs.scut.edu.cn/classic/
logfile=spiderq.log

以“=”作为分割符,左边为key,右边为valve,主要包含的参数内容为:最大的任务数,种子,日志文件,日志等级,深度,模块路径,支持的文件类型,等,以“#”开头的就作为注释。

配置文件结构体如下:

Config * initconfig()
{
Config *conf = (Config *)malloc(sizeof(Config)); conf->max_job_num = 10;
conf->seeds = NULL;
conf->include_prefixes = NULL;
conf->exclude_prefixes = NULL;
conf->logfile = NULL;
conf->log_level = 0;
conf->max_depth = INF;
conf->make_hostdir = 0;
conf->module_path = NULL;
conf->stat_interval = 0;
//conf->modules return conf;
}

是一个全局的结构体,若以类的方式实现则可以设计成单例类,里面的参数主要保存从配置文件中读取到的东西。加载配置文件后,配置文件的参数设置被保存到了Config结构体的,供后面的函数使用

加载配置文件的函数如下:

void loadconfig(Config *conf)
{ FILE *fp = NULL;
char buf[MAX_CONF_LEN+1];
int argc = 0;
char **argv = NULL;
int linenum = 0;
char *line = NULL;
const char *err = NULL; if ((fp = fopen(CONF_FILE, "r")) == NULL) //打开配置文件
{
SPIDER_LOG(SPIDER_LEVEL_ERROR, "Can't load conf_file %s", CONF_FILE);
} while (fgets(buf, MAX_CONF_LEN+1, fp) != NULL)//获取一行到buf
{
linenum++;
line = strim(buf);//去除空格,在qstring中
//过滤#
if (line[0] == '#' || line[0] == '\0') continue;
//count: 分割后的字符串长度
//limit: 分割多少次
argv = strsplit(line, '=', &argc, 1);
if (argc == 2) {
if (strcasecmp(argv[0], "max_job_num") == 0) {
conf->max_job_num = atoi(argv[1]);
}
//extern char *strdup(char *s);
//功 能: 将串拷贝到新建的位置处
//strdup()在内部调用了malloc()为变量分配内存,
//不需要使用返回的字符串时,需要用free()释放相应的内存空间,
//否则会造成内存泄漏
//strcasecmp(忽略大小写比较字符串)
else if (strcasecmp(argv[0], "logfile") == 0) {
conf->logfile = strdup(argv[1]);
} else if (strcasecmp(argv[0], "include_prefixes") == 0) {
conf->include_prefixes = strdup(argv[1]);
} else if (strcasecmp(argv[0], "exclude_prefixes") == 0) {
conf->exclude_prefixes = strdup(argv[1]);
} else if (strcasecmp(argv[0], "seeds") == 0) {
conf->seeds = strdup(argv[1]);
} else if (strcasecmp(argv[0], "module_path") == 0) {
conf->module_path = strdup(argv[1]);
} else if (strcasecmp(argv[0], "load_module") == 0) {
conf->modules.push_back(strdup(argv[1]));
} else if (strcasecmp(argv[0], "log_level") == 0) {
conf->log_level = atoi(argv[1]);
} else if (strcasecmp(argv[0], "max_depth") == 0) {
conf->max_depth = atoi(argv[1]);
} else if (strcasecmp(argv[0], "stat_interval") == 0) {
conf->stat_interval = atoi(argv[1]);
} else if (strcasecmp(argv[0], "make_hostdir") == 0) {
conf->make_hostdir = yesnotoi(argv[1]);
} else if (strcasecmp(argv[0], "accept_types") == 0) {
conf->accept_types.push_back(strdup(argv[1]));
} else {
err = "Unknown directive"; goto conferr;
}
} else {
err = "directive must be 'key=value'"; goto conferr;
} } return; conferr:
SPIDER_LOG(SPIDER_LEVEL_ERROR, "Bad directive in %s[line:%d] %s", CONF_FILE, linenum, err);
}

下面介绍几个函数:

(1)fgets函数是用来获取行的,该函数可读取文件中的一行,并且会包含换行符

(2)strim函数用于去除空格,其实现如下:参数是行指针

//去除空格
char * strim(char *str)
{
char *end, *sp, *ep;
size_t len; sp = str;
end = ep = str+strlen(str)-1;
//从行首开始
while(sp <= end && isspace(*sp)) sp++;
//从行尾开始
while(ep >= sp && isspace(*ep)) ep--;
//计算长度
len = (ep < sp) ? 0 : (ep-sp)+1;
sp[len] = '\0';
return sp;
}

(3)strsplit函数用于分割字符串,实现方法如下:

//切割字符串,函数内申请,函数外释放
//count: 分割后的字符串长度
//limit: 分割多少次
char ** strsplit(char *line, char delimeter, int *count, int limit)
{
char *ptr = NULL, *str = line;
char **vector = NULL; *count = 0;
//strchr函数原型:extern char *strchr(const char *s,char c);查找字符串s中首次出现字符c的位置。
while((ptr = strchr(str, delimeter)))
{
*ptr = '\0';
vector = (char **)realloc(vector,((*count)+1)*sizeof(char *));
vector[*count] = strim(str);//等号前面部分去除空格后放入vector
str = ptr+1;//此时str指向等号后面部分(会继续查找后面的等号)
(*count)++;
if (--limit == 0) break;
}
if (*str != '\0')
{
vector = (char **)realloc(vector,((*count)+1)*sizeof(char *));
vector[*count] = strim(str);//分割空格
(*count)++;
}
return vector;
}

(4)strcasecmp函数是忽略大小写比较字符串,该函数用来比较配置文件的key值

定义函数 int strcasecmp (const char *s1, const char *s2);

函数说明 strcasecmp()用来比较参数s1和s2字符串,比较时会自动忽略大小写的差异。

返回值 若参数s1和s2字符串相等则返回0。s1大于s2则返回大于0 的值,s1 小于s2 则返回小于0的值。

(5)strdup函数

extern char *strdup(char *s);

功 能: 将串拷贝到新建的位置处,strdup()在内部调用了malloc()为变量分配内存,不需要使用返回的字符串时,需要用free()释放相应的内存空间,否则会造成内存泄漏

一只简单的网络爬虫(基于linux C/C++)————配置文件设计及读取的更多相关文章

  1. 一只简单的网络爬虫(基于linux C/C++)————开篇

    最近学习开发linux下的爬虫,主要是参考了该博客及其他一些网上的资料.网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息 ...

  2. 一只简单的网络爬虫(基于linux C/C++)————浅谈并发(IO复用)模型

    Linux常用的并发模型 Linux 下设计并发网络程序,有典型的 Apache 模型( Process Per Connection ,简称 PPC ), TPC ( Thread Per Conn ...

  3. 一只简单的网络爬虫(基于linux C/C++)————支持动态模块加载

    插件在软件设计中有很大的好处,可以方便地扩展各种功能,使用插件技术能够在分析.设计.开发.项目计划.协作生产和产品扩展等很多方面带来好处: (1)结构清晰.易于理解.由于借鉴了硬件总线的结构,而且各个 ...

  4. 一只简单的网络爬虫(基于linux C/C++)————socket相关及HTTP

    socket相关 建立连接 网络通信中少不了socket,该爬虫没有使用现成的一些库,而是自己封装了socket的相关操作,因为爬虫属于客户端,建立套接字和发起连接都封装在build_connect中 ...

  5. 一只简单的网络爬虫(基于linux C/C++)————守护进程

    守护进程,也就是通常说的Daemon进程,是Linux中的后台服务进程.它是一个生存期较长的进程,通常独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程常常在系统引导装入时启动, ...

  6. 一只简单的网络爬虫(基于linux C/C++)————读取命令行参数及日志宏设计

    linux上面的程序刚开始启动的时候一般会从命令行获取某些参数,比如以守护进程运行啊什么的,典型的例子就是linux下的man,如下图所示 实现该功能可以使用getopt函数实现,该函数在头文件uni ...

  7. 一只简单的网络爬虫(基于linux C/C++)————利用正则表达式解析页面

    我们向一个HTTP的服务器发送HTTP的请求后,服务器会返回可能一个HTML页面(当然也可以是其他的资源),我们可以利用返回的HTML页面,在其中寻找其他的Url,例如我们可以这样在浏览器上查看一下H ...

  8. 一只简单的网络爬虫(基于linux C/C++)————线程相关

    爬虫里面采用了多线程的方式处理多个任务,以便支持并发的处理,把主函数那边算一个线程的话,加上一个DNS解析的线程,以及我们可以设置的max_job_num值,最多使用了1+1+max_job_num个 ...

  9. 一只简单的网络爬虫(基于linux C/C++)————Url处理以及使用libevent进行DNS解析

    Url处理 爬虫里使用了两个数据结构来管理Url 下面的这个数据结构用来维护原始的Url,同时有一个原始Url的队列 //维护url原始字符串 typedef struct Surl { char * ...

随机推荐

  1. javascript入门 之 zTree(十三 移动/复制事件)

    <!DOCTYPE html> <HTML> <HEAD> <TITLE> ZTREE DEMO - copyNode / moveNode</T ...

  2. android所有颜色

    <?xml version="1.0" encoding="utf-8" ?> <resources> <color name=& ...

  3. html字体大小与颜色设置

    代码架构:<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> //浏览器识 ...

  4. php.ini配置文件详解(基于5.2.17版本)

    [PHP] ;;;;;;;;;;;;;;;;;;;; About php.ini ;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;; 关于php.ini文件 ;;;;; ...

  5. Java学习成长第一集

    由于最近所在项目组的项目临近结尾,所以有时间对自己近来的学习做个总结.不得不说,程序员不学习就退步这句话是真的很让人信服!自己入行将近一年的时间,所学的就是Java开发的专业,很羞愧的是现在的自己能力 ...

  6. 从python爬虫以及数据可视化的角度来为大家呈现“227事件”后,肖战粉丝的数据图

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取t.cn ...

  7. CodeForces - 913C (贪心)

    点完菜,他们发现好像觉得少了点什么? 想想马上就要回老家了某不愿透露姓名的林姓学长再次却陷入了沉思......... 他默默的去前台打算点几瓶二锅头. 他发现菜单上有n 种不同毫升的酒. 第 i 种有 ...

  8. gridview 合并单元格后,选中颜色重新绘制

    gv_docargo.RowStyle += OnRowStyle; private void OnRowStyle(object sender, DevExpress.XtraGrid.Views. ...

  9. 基于TextRank算法的文本摘要

    本文介绍TextRank算法及其在多篇单领域文本数据中抽取句子组成摘要中的应用. TextRank 算法是一种用于文本的基于图的排序算法,通过把文本分割成若干组成单元(句子),构建节点连接图,用句子之 ...

  10. 推荐一个小而美的Python代码格式化工具

    代码可读性是评判代码质量的标准之一,有一个衡量代码质量的标准是 Martin 提出的 “WFT” 定律,即每分钟爆出 “WTF” 的次数.你在读别人代码或者做 Code Review 的时候有没有 “ ...