nodejs+cheerio自动爬取小说内容并写入文件小demo

9 篇文章 0 订阅
4 篇文章 1 订阅

爬取小说

这次分享一个爬取一个网站小说的demo,刚开始学习爬虫的朋友也可以参考思路去编写自己的程序,爬取思路——
首先,找到你要爬取的网站的链接,然后获取书籍的链接;
二、每本书都有一个自己的链接;
三、然后该书的链接的内容会包含目录列表链接
四、我们便可以借用书籍的链接去获取目录链接
五、然后根据目录链接去获取目录内容,然后讲内容爬取出来并写入文件中就完成爬取了
基本就是这五部就可以完成爬取任务了

获取书籍链接代码段
var data = [];
	for (var i = 1; i < 2; i++) {
	//此处链接就是包含很多书籍的链接
		var d = await getHttpData('http://book.zongheng.com/store/c1/c1003/b0/u0/p' + i + '/v0/s1/t0/u0/i1/ALL.html',
			getBookName);
			//es6的数组拼接
		data = [...data, ...d];
	}
//这是获取书名部分代码
function getBookName($) {  //参数$是爬取的内容,下面是处理,匹配出我们要的信息
	var reg = /http.+.html/g;
	var url = [];
	
	var _this = $('.store_collist .bookbox');
	//获取书名数组
	//这里基本就是html的DOM操作了,就不解释了
	$('.store_collist .bookbox').each(function(index, ele) {
		
		var _url = $(ele).find('.bookname').html().match(reg);
		var bookName = $(ele).find('.bookname a').text();
		// console.log(bookName)
		var author = $(ele).find('.bookilnk a:first-child').text();
		_url[0] = _url[0].replace('com/book', "com/showchapter");
		//图片链接
		var imgUrl = $(ele).find('.bookimg img').prop('src');
		//获取本书描述
		var describe = $(ele).find('.bookintro').text();
		//将数据保存到数组,最终返回一个对象数组
		var obj = {
			bookUrl: _url[0],
			bookName: bookName,
			author: author,
			imgSrc: imgUrl,
			describe: describe,
			childrenUrl: []
		}
		url.push(obj);
	})
	return url;
}
获取目录链接
for (var i = 0; i < data.length; i++) {
		var d1 = await getHttpData(data[i].bookUrl, getChapterList);
		data[i].childrenUrl = d1;

	}
//获取目录函数,跟上面的书籍链接一样的方式
function getChapterList($) {
	var url = [];
	var reg = /http.+.html/g;
	$('.chapter-list .col-4').each(function(index, ele) {
		//用正则匹配出我们要的链接
		var str_url = $(this).html().match(reg);
		url.push(str_url[0]);

	});
	return url;
	//书名数组->目录数组
}
获取内容
for (var i = 0; i < data.length; i++) {
		for (var j = 0; j < data[i].childrenUrl.length; j++) {

			var obj = await getHttpData(data[i].childrenUrl[j], getChapterContent);
			var p_txt = `aa/${data[i].bookName}-${data[i].author}/${obj.txtName}`
			//先判断上级目录是否存在,不存在就创建

			if (!fs.existsSync(`aa/${data[i].bookName}-${data[i].author}`)) {
				try {
					fs.mkdirSync(`aa/${data[i].bookName}-${data[i].author}`)
				} catch (e) {
					console.log(e)
				}
			}
			//如果问价存在,就不写

			if (!fs.existsSync(p_txt)) {
				try {
					fs.writeFileSync(p_txt, obj.content)
				} catch (e) {
					console.log(e)
				}
			}

			//用来控制时间间隔为1s,因为如果不控制速度的话,会被服务器拒绝
			for (var k = 0; k < 1000000000; k++) {}
		}
	}
//爬取内容方法
function getChapterContent($) {

	//获取章节标题
	var reg1 = /(?:\s)*/g;

	var title = $('.reader_box .title_txtbox').text();
	//作者

	var author = $('.bookinfo a:first-child').text();
	//字数

	var number = $('.bookinfo span:nth-child(2)').text()
	//时间

	var time = $('.bookinfo span:nth-child(3)').text();
	//内容

	var content = $('.reader_box .content').html();
	var info = `${title}-${number}字-${time}`;
	content = `<h5>${info}</h5>${content}`;
	//正则匹配,去掉一起不合法的字符并替换为空格
	title = title.replace(/\?|\!|\"|\:|\<|\>|\||\\|\//g, " ");
	
	var obj = {
		txtName: title + ".txt",
		content: content
	}
	console.log("获取到" + info)
	return obj;

}*斜体样式*

*整个爬取就是分为三部分,首先获取书籍然后根据书籍获取目录

然后根据目录
获取内容
,由于这三部分的数据获取需要一个顺序,所以

我采用了promise对象讲一些异步操作转换成同步,不理解如何转同步的朋友

可以先不管,直接照着用就行了,有些地方不需要同步的,只是为了让这个爬取过程编程顺序过程,会看的更仔细

注:有一段空循环代码,是为了控制每次爬取间隔为1s,加上去用来阻塞代码运行的,这里不能用setTimeout是异步的,不会阻塞,不控制爬取速度会被服务器禁止访问

以下是完整的代码

const http = require('http');
const fs = require('fs');
const cheerio = require('cheerio');

function Pac() {}
//爬取内容,用promise对象包装异步获取数据的操作
function getHttpData(http1, callback) {
	//爬取内容
	// console.log(this);
	var p = new Promise(function(resolve, reject) {
		http.get(http1, function(req, res) {
			var html = '';
			req.on('data', function(data) {
				html += data;
			})
			req.on('end', function() {
				// console.log(html,);
				//爬取完毕装载到,并返回装载后的对象
				//调用处理函数来处理装载的数据


				const $ = cheerio.load(html, {
					decodeEntities: false
				})
				var d = callback($);
				resolve(d);
			})
		})
	}).catch((err) => {
		console.log(err);
	})
	return p;
}
//获取章节内容
function getChapterContent($) {

	//获取章节标题
	var reg1 = /(?:\s)*/g;

	var title = $('.reader_box .title_txtbox').text();
	//作者

	var author = $('.bookinfo a:first-child').text();
	//字数

	var number = $('.bookinfo span:nth-child(2)').text()
	//时间

	var time = $('.bookinfo span:nth-child(3)').text();
	//内容

	var content = $('.reader_box .content').html();
	var info = `${title}-${number}字-${time}`;
	content = `<h5>${info}</h5>${content}`;
	//正则匹配,去掉一起不合法的字符并替换为空格
	title = title.replace(/\?|\!|\"|\:|\<|\>|\||\\|\//g, " ");
	
	var obj = {
		txtName: title + ".txt",
		content: content
	}
	console.log("获取到" + info)
	return obj;

}
//获取章节连接
function getChapterList($) {
	var url = [];
	var reg = /http.+.html/g;
	$('.chapter-list .col-4').each(function(index, ele) {
		//用正则匹配出我们要的链接
		var str_url = $(this).html().match(reg);
		url.push(str_url[0]);

	});
	return url;
	//书名数组->目录数组
}

function getBookName($) {
	var reg = /http.+.html/g;
	var url = [];
	
	var _this = $('.store_collist .bookbox');
	//获取书名数组
	$('.store_collist .bookbox').each(function(index, ele) {
		
		var _url = $(ele).find('.bookname').html().match(reg);
		var bookName = $(ele).find('.bookname a').text();
		// console.log(bookName)
		var author = $(ele).find('.bookilnk a:first-child').text();
		_url[0] = _url[0].replace('com/book', "com/showchapter");
		//图片链接
		var imgUrl = $(ele).find('.bookimg img').prop('src');
		//获取本书描述
		var describe = $(ele).find('.bookintro').text();
	
		var obj = {
			bookUrl: _url[0],
			bookName: bookName,
			author: author,
			imgSrc: imgUrl,
			describe: describe,
			childrenUrl: []
		}
		url.push(obj);
	})
	return url;
}

Pac.start = async function() {
	//拿到书名数据
	var data = [];
	for (var i = 1; i < 2; i++) {
		var d = await getHttpData('http://book.zongheng.com/store/c1/c1003/b0/u0/p' + i + '/v0/s1/t0/u0/i1/ALL.html',
			getBookName);
			//es6的数组拼接
		data = [...data, ...d];
	}
	
	//遍历书名,获取目录连接
	for (var i = 0; i < data.length; i++) {
		var d1 = await getHttpData(data[i].bookUrl, getChapterList);
		data[i].childrenUrl = d1;

	}
	//设置速度为1s爬取一次
	//遍历目录链接,获取内容
	for (var i = 0; i < data.length; i++) {
		for (var j = 0; j < data[i].childrenUrl.length; j++) {

			var obj = await getHttpData(data[i].childrenUrl[j], getChapterContent);
			var p_txt = `aa/${data[i].bookName}-${data[i].author}/${obj.txtName}`
			//先判断上级目录是否存在,不存在就创建

			if (!fs.existsSync(`aa/${data[i].bookName}-${data[i].author}`)) {
				try {
					fs.mkdirSync(`aa/${data[i].bookName}-${data[i].author}`)
				} catch (e) {
					console.log(e)
				}
			}
			//如果问价存在,就不写

			if (!fs.existsSync(p_txt)) {
				try {
					fs.writeFileSync(p_txt, obj.content)
				} catch (e) {
					console.log(e)
				}
			}

			//用来控制时间间隔为1s,因为如果不控制速度的话,会被服务器拒绝
			for (var k = 0; k < 1000000000; k++) {}
		}
	}
	console.log("爬取完成")
}
Pac.start();



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值