今天原本是想寫一篇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,若有不足之處,請斧正