今天原本是想写一篇webpack的博客的,而后呢因为担忧拉下或者讲不清楚一些细节,本着负责任的原则,想在网上复习一下再写css
而后我找到了一个webpack的网站,可是正在我看的津津有味的时候,网页忽然给我蹦出来一个弹窗html
大概是这么个意思,我在控制台删除元素或者试图取消该网站的监听事件都无果,删不干净,总之就是不让你舒舒服服的往下看,不嫌墨迹的话也能看node
不是说好的技术无界限的嘛,为啥又要这样。。。,难不成还要买一本?jquery
当发现他实际上是有完整文章渲染出来,只是阻拦了往下浏览的时候,我得钱包提醒了我一下白嫖的时候到了webpack
这么多网页所有手动保存是比较墨迹的,显然写一个node爬虫是比较不错的选择ios
主要用到的模块以下web
npm i cheerio axios const cheerio = require('cheerio') 获取页面内容 const axios = require('axios'); const fs = require('fs');
这里请求的工具选择的axios,由于平时用到的比较多,比较熟悉npm
fs 操做本地文件,node的一个内置的模块axios
而后cheerio浏览器
cheerio是jquery核心功能的一个快速灵活而又简洁的实现,主要是为了用在服务器端须要对DOM进行操做的地方
在node环境里边直接抓dom是比较墨迹的,cheerio这个模块能够用来解析html,和jquery同样。
有了这个就好说了,首先把整个网站的导航拿下来,而后根据网站的导航地址遍历对应的链接,最后根据本身的需求把须要的内容下载到本地就能够了
上边说了那么多,如今进入正题
// 配置一下请求地址 `axios.defaults.baseURL = 'https://xxxxxx.cn/'` `axios.get('/').then(res => {console.log(res.data)})`
尝试着请求一下首页,获得结果以下
是咱们想要的东西没错
而后接下来 咱们按照jquery的方法 找到导航那块html
假如说咱们须要的模块在.summary
这个class下边,而后须要获取他里边全部有内容的标题路径的时候,代码以下
/** * @Date: 2020-04-10 16:11:02 * @information: 获取页面内容 */ async init() { let result = await axios.get('/') let page = result.data let $ = cheerio.load(page) let navNode = $('.summary') // 递归标题和路径 navNode.children().each((navIndex, item) => { let itemNode = $(item) let ulNode = itemNode.find('ul') if (!ulNode.length) return // 获取全部大标题 let title = itemNode.find('a').first().text().replace(/\s/g, "") this.urlMap.set(title, new Map()) let contentNode = $(ulNode) contentNode.children().each((contentIndex, item) => { let body = $(item).find('a') let contentMap = this.urlMap.get(title) contentMap.set(body.text().replace(/\s/g, ""), body.attr('href')) }) }) }
打印一下结果
在获取完导航的路由以后剩下的就是遍历取内容了,首先建立一个保存文件的文件夹路径
// 建立保存的路径文件夹 let writeUrl = `xxxxxx` //在建立以前判断一下是否是已经有了这个文件夹 let hasDir = fs.existsSync(writeUrl); !hasDir && fs.mkdirSync(writeUrl);
而后从刚才获取的导航的map 里边读取路径
``` // 创建子文件夹和内容 this.urlMap.forEach((item, titleIndex) => { let dirName = `${writeUrl}\\${titleIndex}` let hasSubDir = fs.existsSync(dirName); !hasSubDir && fs.mkdirSync(dirName) // 抓文件并写文件 item.forEach(async (item, index) => { let result = await axios.get(`/${encodeURI(item)}`) let page = result.data let $ = cheerio.load(page) let contentNode = $('.search-noresults') fs.writeFile(`${dirName}\\${index}.html`, contentNode, () => { // console.log(`${index}:写入成功`) }) }) }) ```
把请求到的页面拿到对应dom,直接往html里边一塞,完活,打开看一下
emm 看却是能看 不过样式实在是太难看了,打开爬取的网站的源代码找到他的资源路径加进去
` contentNode.before('<link rel="stylesheet" href="https://xxxxxx/style.css"></link>')`
还有图片加载不出来的问题,同理查找全部的img标签,若是有图片的话把src属性的值拿下来取对应的地址下载
``` let imgNodeArr = contentNode.find('img') if (!imgNodeArr.length) return imgNodeArr.each(async (i, el) => { let src = $(el).attr('src') let imgPath = `/${encodeURI(titleIndex.split("/")[0].replace('第', "").replace('章', ""))}/${encodeURI(src)}` if ($(el).attr('src').includes('http')) return // 下载图片存储到本地 let result = await axios.get(`${imgPath}`, { responseType: 'stream' }) let hasImgDir = fs.existsSync(`${dirName}\\img`); !hasImgDir && fs.mkdirSync(`${dirName}\\img`) result.data.pipe(fs.createWriteStream(`${dirName}/${src}`)); // console.log(`写入图片成功:${dirName}\\${src}`) }) ```
http地址的图片就不须要下载了,既然他能拿到,那么我们直接用就行了
这里请求的时候必定要加{ responseType: 'stream' }
,否则的话图片下载回来会打不开格式
`result.data.pipe(fs.createWriteStream(`${dirName}/${src}`));`
把文件流写入到文件里边生成图片,运行一下看看效果
ok,至此一个简单的爬虫就完成了,最后放上效果图
喜欢的点个赞把
完事撒花o( ̄▽ ̄)ブ,过几天继续webpack,若有不足之处,请斧正