使用 node 爬取数据
准备用electron
制作一个小说阅读工具练练手,那么首先要解决的就是数据问题,也就是小说的文本。
这里准备使用 node 对小说网站进行爬虫爬取,尝试爬下一本小说,数据就不存放数据库了,先使用txt
作为文本存储
在node
中对于网站的请求,本身就存在http
和https
库,内部含有request
请求方法。
实例:
request = https.request(TestUrl, { encoding:'utf-8' }, (res)=>{
let chunks = ''
res.on('data', (chunk)=>{
chunks += chunk
})
res.on('end',function(){
console.log('请求结束');
})
})
复制代码
但是也就到此为止了,只是存取了一个html
的文本数据,并不能够对内部元素进行提取之类的工作(也可以正则拿,但是太过复杂)。
我将访问到的数据通过fs.writeFile
方法存储起来了,这只是整个网页的html
但是我想要的还有各个章节中的内容,这样一来就需要获取章节的超链接,组成超链接链表进去爬取
cheerio 库
所以,这里就要介绍一个 js 的库了,cheerio
官方文档:https://cheerio.js.org/
中文文档:https://github.com/cheeriojs/cheerio/wiki/Chinese-README
在文档中,可以使用示例进行调试
使用 cheerio 解析 HTML
cheerio 解析 html 时,获取 dom 节点的方式与jquery
相似。
根据之前获取到的书籍首页的 html,查找自己想要的 dom 节点数据
const fs = require('fs')
const cheerio = require('cheerio');
// 引入读取方法
const { getFile, writeFun } = require('./requestNovel')
let hasIndexPromise = getFile('./hasGetfile/index.html');
let bookArray = [];
hasIndexPromise.then((res)=>{
let htmlstr = res;
let $ = cheerio.load(htmlstr);
$(".listmain dl dd a").map((index, item)=>{
let name = $(item).text(), href = 'https://www.shuquge.com/txt/147032/' + $(item).attr('href')
if (index > 11){
bookArray.push({ name, href })
}
})
// console.log(bookArray)
writeFun('./hasGetfile/hrefList.txt', JSON.stringify(bookArray), 'w')
})
复制代码
打印一下信息
同时可以将这些信息也存储起来, 方便后续读取,否则如果之后再次运行还要重新爬取
现在章节数和章节的链接都有了,那么就可以获取章节的内容了。
因为批量爬取最后需要 IP 代理,这里还没准备,暂时先写获取某一章节小说的内容方法
爬取某一章节的内容其实也比较简单:
// 爬取某一章节的内容方法
function getOneChapter(n) {
return new Promise((resolve, reject)=>{
if (n >= bookArray.length) {
reject('未能找到')
}
let name = bookArray[n].name;
request = https.request(bookArray[n].href, { encoding:'gbk' }, (res)=>{
let html = ''
res.on('data', chunk=>{
html += chunk;
})
res.on('end', ()=>{
let $ = cheerio.load(html);
let content = $("#content").text();
if (content) {
// 写成txt
writeFun(`./hasGetfile/${name}.txt`, content, 'w')
resolve(content);
} else {
reject('未能找到')
}
})
})
request.end();
})
}
getOneChapter(10)
复制代码
爬取效果:
这样,就可以根据上面的方法,来创造一个调用接口,传入不同的章节参数,获取当前章节的数据
const express = require('express');
const IO = express();
const { getAllChapter, getOneChapter } = require('./readIndex')
// 获取章节超链接链表
getAllChapter();
IO.use('/book',function(req, res) {
// 参数
let query = req.query;
if (query.n) {
// 获取某一章节数据
let promise = getOneChapter(parseInt(query.n - 1));
promise.then((d)=>{
res.json({ d: d })
}, (d)=>{
res.json({ d: d })
})
} else {
res.json({ d: 404 })
}
})
//服务器本地主机的数字
IO.listen('7001',function(){
console.log("启动了。。。");
})
复制代码
效果:
评论