百科词条爬虫
一、爬取的关键要素
每个词条的词条名、词条描述、词条链接。
二、爬取词条,如何存储?
1、cname标签,description标签,url标签, 爬取以后使用这种格式存储,方便我们使用,可以用正则表达式匹配出我们需要的内容。
2、词条数据存储格式
词条名 词条描述 词条链接
三、词条爬虫的工作模式
1、种子URL (Original URL) 爬虫的工作起点,处理的第一条链接,种子URL是精心挑选包含更多链接数据的URL(指向网页的链接)。
2、一般的爬虫里面都会有两个容器
u_container:该容器存储未下载的,未解析的URL。
p_container:存储已下载,已解析的URL。
我们的种子URL是不可以直接放到u_container中的,因为爬虫中有很重要的一环就是去重,因为这个A词条点击以后里面比如包含了BCD三个其他的词条我们点击C词条进入它的页面,这里面也有可能又包含了BD词条,否则就会造成大量的重复下载。
3、去重模块
将URL输入到去重模块,去重模块先到p_container中检测该URL是否存在,再到u_container中检测,都不存在,将该URL添加到u_container中。
4、进入下载以后,(下载模块不再赘述)得到词条的网页源码,然后对网页源码进行解析,得到我们需要的内容。
解析流程:解析器(正则技术:匹配提取关键数据)
1)内容解析:词条名、词条描述、词条链接,save模块保存,注意存储格式。
2)链接解析:爬虫是需要拓扑的,从一个网页链接中解析中它有的新的链接。
URL(O_URL)->去重( p_container+u_container)->下载(网页源码)->解析(内容解析+链接解析)->URL(N_URL)->去重->下载->解析->URL-> … …
我们需要对链接解析进行控制,因为每次解析都会产生很多新的链接,u_container和p_container之间严重的使用不平衡,如果一直解析,u_container分分钟就会爆满。而下载相对较慢,所以我们对链接解析进行限制,如果u_container中未解析的URL数量到达了某个数量,那么就不再进行链接解析(内容是一直要解析的),等数量降下来再继续。
typedef struct { url_t *node_queue; int front; int rear; int max; int cur; }container_t; //容器 //容器创建初始化 container_t *spider_container_create(int); //容器添加节点 int spider_container_setnode(container_t* , url_t); //从容器中获取 int spider_container_getnode(container_t* ,url_t*); // URL去重校验并添加到容器中 , 成功添加返回0 , 重复则失败返回-1 int spider_remove_duplication(container_t* ,container_t* ,const char *); //链接解析及内容解析 int spider_analytical_html(url_t*, container_t* ,container_t* ); //爬虫控制器,抓取过程 int spider_url_controler(const char *);
四、解析模块代码
#includeint spider_analytical_html(url_t* node, container_t* u_ct, container_t* p_ct) { //词条名:(网络爬虫) cnum = 2 匹配1次 //词条描述: cnum = 2 meta标签没有尾 匹配1次 //更多词条链接:链接标题 cnum = 2 //匹配n次 //打开网页源码 int fd = open(node->save_file,O_RDONLY); int fsize = lseek(fd,0,SEEK_END); //将网页源码数据映射到映射内存 char *pstring = mmap(NULL ,fsize ,PROT_READ ,MAP_PRIVATE ,fd ,0); char *jstr = pstring; //多次匹配 涉及偏移 url_t rnode; //正则准备 const char *h1_pst = "\([^<]\+\?\)"; const char *des_pst = ""; const char *a_pst = "]\+\?href="\(/item/[^"]\+\?\)"[^>]\+\?>[^<]\+\?"; regex_t h_reg,d_reg,a_reg; int cnum = 2; regmatch_t h_ma[cnum]; regmatch_t d_ma[cnum]; regmatch_t a_ma[cnum]; //匹配成功 传出位置数组 char h1[1024]; //标题 h1 char url[4096]; // 超链接 a标签 char desc[4096]; //描述 meta bzero(h1,1024); bzero(url,4096); bzero(desc,4096); regcomp(&h_reg,h1_pst,0); regcomp(&d_reg,des_pst,0); regcomp(&a_reg,a_pst,0); if((regexec(&h_reg,pstring,cnum,h_ma,0)) == 0) snprintf(h1,h_ma[1].rm_eo - h_ma[1].rm_so +1,"%s",pstring +h_ma[1].rm_so); if((regexec(&d_reg,pstring,cnum,d_ma,0)) == 0){ snprintf(desc,d_ma[1].rm_eo - d_ma[1].rm_so +1,"%s",pstring +d_ma[1].rm_so); } //控制 new url解析 if(u_ct->cur < 100){ //链接要匹配n次 while((regexec(&a_reg,pstring,cnum,a_ma,0)) == 0){ snprintf(url,a_ma[1].rm_eo -a_ma[1].rm_so + 24,"https://baike.baidu.com%s",pstring+a_ma[1].rm_so); //将新的url去重添加到容器中 if(u_ct->cur != u_ct->max){ if(!spider_remove_duplication(u_ct,p_ct,url)){ strcpy(rnode.alpha_url,url); spider_container_setnode(u_ct,rnode); } bzero(url,sizeof(url)); pstring+=a_ma[0].rm_eo; //向后偏移寻找下一个a标签 //解析完毕 是否删除文件 unlink(node->save_file); }else break; } } printf("Analytical_Html TITLE[%s]n",h1); printf("Analytical_Html DEscriptION[%s]n",desc); printf("Analytical_Html This URL [%s]n",node->alpha_url); regfree(&h_reg); regfree(&d_reg); regfree(&a_reg); munmap(jstr,fsize); //释放映射 jstr首地址 close(fd); return 0; }
完整代码链接:https://github.com/Birdbird-66/BirdBird-A.git
运行部分截图
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)