网络爬虫4 --- 百科词条爬虫 (爬取的关键要素:每个词条的词条名、词条描述、词条链接)

网络爬虫4 --- 百科词条爬虫 (爬取的关键要素:每个词条的词条名、词条描述、词条链接),第1张

网络爬虫4 --- 百科词条爬虫 (爬取的关键要素:每个词条的词条名、词条描述、词条链接

百科词条爬虫
一、爬取的关键要素
每个词条的词条名、词条描述、词条链接。
二、爬取词条,如何存储?
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 *);

四、解析模块代码

#include

int 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

运行部分截图

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5689362.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-17
下一篇 2022-12-17

发表评论

登录后才能评论

评论列表(0条)

保存