网络爬虫二

网络抓取系统分为核心和扩展组件两部分。核心部分是一个精简的、模块化的爬虫实现,而扩展部分则包括一些便利的、实用性的功能。目标是尽量的模块化,并体现爬虫的功能特点。这部分提供简单、灵活的API,在基本不改变开发模式的情况下,编写一个爬虫。
扩展组件部分提供一些扩展的功能,内置了一些常用的组件,便于对爬虫进行功能扩展。
蜘蛛主要功能模块如下:
这里写图片描述
调度器
调度器负责管理待抓取的URL,以及去重的工作。调度器使用内存队列来管理URL,并进行去重。
下载器
下载器是爬虫的基础。下载页面之后才能进行其他后续操作。
页面处理器
一般来说,我们最终需要的都不是原始的HTML页面。我们需要对爬到的页面进行分析,转化成结构化的数据,并存储下来
持久化器
持久化器负责抽取结果的处理,包括计算、持久化到文件、数据库等。

当我们设计好程序框架之后就要开始实现它了。第一步当然是要实现主程序的流程框架。之后我们逐渐填充每个流程的细节和其需要调用的模块。
主程序的流程如下:
1、 解析命令行参数,并根据参数跳转到相应的处理分支
2、 解析配置文件
3、 载入处理模块
4、 加载种子URL
5、 启动抓取任务
主程序的代码如下:

int main(int argc, void *argv[])  
{  
   struct epoll_event events[10];  
   int daemonized = 0;  
   char ch;  

   while ((ch = getopt(argc, (char* const*)argv, "vhd")) != -1) {  
        switch(ch) {  
            case 'v':  
                version();  
                break;  
            case 'd':  
                daemonized = 1;  
                break;  
            case 'h':  
            case '?':  
            default:  
                usage();  
        }  
   }  

   g_conf = initconfig();  
   loadconfig(g_conf);  

   set_nofile(1024);  

   vector<char *>::iterator it = g_conf->modules.begin();  
   for(; it != g_conf->modules.end(); it++) {  
        dso_load(g_conf->module_path, *it);  
   }  

   if (g_conf->seeds == NULL) {  
        SPIDER_LOG(SPIDER_LEVEL_ERROR, "Wehave no seeds, Buddy!");  
   } else {  
        int c = 0;  
        char ** splits =strsplit(g_conf->seeds, ',', &c, 0);  
        while (c--) {  
            Surl * surl = (Surl*)malloc(sizeof(Surl));  
            surl->url =url_normalized(strdup(splits[c]));  
            surl->level = 0;  
            surl->type = TYPE_HTML;  
            if (surl->url != NULL)  
                push_surlqueue(surl);  
       }  
   }         

   if (daemonized)  
        daemonize();  

   chdir("download");  

   int err = -1;  
   if ((err = create_thread(urlparser, NULL, NULL, NULL)) < 0) {  
        SPIDER_LOG(SPIDER_LEVEL_ERROR,"Create urlparser thread fail: %s", strerror(err));  
   }  

   int try_num = 1;  
   while(try_num < 8 && is_ourlqueue_empty())  
        usleep((10000 << try_num++));  

   if (try_num >= 8) {  
        SPIDER_LOG(SPIDER_LEVEL_ERROR, "NOourl! DNS parse error?");  
   }  

   if (g_conf->stat_interval > 0) {  
        signal(SIGALRM, stat);  
        set_ticker(g_conf->stat_interval);  
   }  

   int ourl_num = 0;  
   g_epfd = epoll_create(g_conf->max_job_num);  

   while(ourl_num++ < g_conf->max_job_num) {  
        if (attach_epoll_task() < 0)  
            break;  
   }  

   int n, i;  
   while(1) {  
        n = epoll_wait(g_epfd, events, 10,2000);  
        printf("epoll:%d\n",n);  
        if (n == -1)  
            printf("epollerrno:%s\n",strerror(errno));  
        fflush(stdout);  

        if (n <= 0) {  
            if (g_cur_thread_num <= 0&& is_ourlqueue_empty() && is_surlqueue_empty()) {  
                sleep(1);  
                if (g_cur_thread_num <= 0&& is_ourlqueue_empty() && is_surlqueue_empty())  
                    break;  
            }  
        }  

        for (i = 0; i < n; i++) {  
            evso_arg * arg = (evso_arg*)(events[i].data.ptr);  
            if ((events[i].events &EPOLLERR) ||  
                (events[i].events &EPOLLHUP) ||  
                (!(events[i].events &EPOLLIN))) {  
                SPIDER_LOG(SPIDER_LEVEL_WARN,"epoll fail, close socket %d",arg->fd);  
                close(arg->fd);  
                continue;  
            }  
            epoll_ctl(g_epfd, EPOLL_CTL_DEL,arg->fd, &events[i]); /* del event */  

            printf("helloepoll:event=%d\n",events[i].events);  
            fflush(stdout);  
            create_thread(recv_response, arg,NULL, NULL);  
        }  
   }  

   SPIDER_LOG(SPIDER_LEVEL_DEBUG, "Task done!");  
   close(g_epfd);  
   return 0;  
}  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值