NodeJs ES6 写简单爬虫 爬小说网站《我当方士那些年》
個人網站地址 www.wenghaoping.com
Vue + express + Mongodb構建 請大家多支持一下。
先上代碼,然后在慢慢逼逼
Git地址,有需要的Clone
==先從小說網站開始練手,然后爬電影網站,可以下最新的電影,這是我的需求。哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈==
演示:
大致流程
1 獲取 URLs 列表(請求資源 http模塊) 2 根據 URLs 列表獲取相關頁面源碼(可能遇到頁面編碼問題,iconv-lite 模塊) 3 源碼解析,獲取小說信息( cheerio 模塊) 4 保存小說信息到 txt 文件,并且加適當修飾以及章節信息(寫文件 fs)
具體
根據小說的導航頁,獲取到當前章節,然后獲取鏈接
首選通過 http.get() 方法獲取頁面源碼 獲取到源碼,打印發現中文亂碼,查看發現 ==charset = 'gbk'==,需要進行轉碼 使用 iconv-lite 模塊進行轉碼,中文顯示正常后開始解析源碼,獲取需要的 URL, 為了更方便地解析,需要引進 cheerio 模塊,cheerio 可以理解為運行在后臺的 jQuery,用法與 jQuery 也十分相似,熟悉 jQuery 的同學可以很快的上手
// 請求標題 let titleRequest = (url) => {return new Promise((resolve, reject) => {//采用http模塊向服務器發起一次get請求http.get(url, function (res) {let html = ''; //用來存儲請求網頁的整個html內容//監聽data事件,每次取一塊數據res.on('data', function (chunk) {html += iconv.decode(chunk, 'GBK');});//監聽end事件,如果整個網頁內容的html都獲取完畢,就執行回調函數res.on('end', function () {let $ = cheerio.load(html); //采用cheerio模塊解析html// 總的長度endNumber = $('#list a').length;let title = $('#list a').eq(number).text();let mainUrl = baseUrl + $('#list a').eq(number).attr('href');let item = {// 小說標題title: title,// 小說詳情mainUrl: mainUrl,//i是用來判斷獲取了多少篇文章i: number}// console.log(item); //打印新聞信息resolve(item);});}).on('error', function (err) {console.log(err);reject(err);});}); };復制代碼將源碼加載進 cheerio,分析了源碼后得知所有章節信息都存于被 div 包裹的 a 標簽中,通過 cheerio 取出符合條件的 a 標簽組,進行遍歷,獲取章節的 title 和 URL,保存為對象,存進數組,(因為鏈接中存儲的 URL 不完整,所以存儲時需要補齊) 然后在寫一個獲取詳情的爬蟲
// 請求內容 let mainRequest = (mainUrl) => {return new Promise((resolve, reject) => {//采用http模塊向服務器發起一次get請求http.get(mainUrl, function (res) {let html = ''; //用來存儲請求網頁的整個html內容//監聽data事件,每次取一塊數據res.on('data', function (chunk) {html += iconv.decode(chunk, 'GBK');});//監聽end事件,如果整個網頁內容的html都獲取完畢,就執行回調函數res.on('end', function () {let $ = cheerio.load(html); //采用cheerio模塊解析htmllet detail = $('#content').text().replace(/\s+/g,"\r\n\r\n    ");// console.log(detail); // 打印詳情resolve(detail);});}).on('error', function (err) {console.log(err);reject(err);});}); } 復制代碼下面是所有代碼
const http = require('http'); const fs = require('fs'); const cheerio = require('cheerio'); const iconv = require('iconv-lite'); let baseUrl='http://www.biquge.com.tw';// 筆趣閣公共地址 let url='http://www.biquge.com.tw/3_3142/';// 筆趣閣 《我當方士那些年》 首頁 ===== 要變小說,只需要更改此處地址就可以 let urlOne = 'http://www.biquge.com.tw/3_3142/1788029.html'; // 筆趣閣 《我當方士那些年》 第一章地址 測試用 let number = 0; // 請求次數 let endNumber = 0; // 總數 或者可以控制爬取次數。// 開始請求,并且寫入數據 let startRequest = async function(url) {let title = await titleRequest(url);let detail = await mainRequest(title.mainUrl);console.log(`開始爬取 ${title.title}`);number++;await savedContent('./data/', `${number} ${title.title}`, detail);console.log(`寫入 ${title.title}`);if (number <= endNumber) {startRequest(url);} else {console.log('===========================全部完成===========================');} };// 在本地存儲 let savedContent = (path, title, detail) => {fs.appendFile(path + title + '.txt', detail, (err) => {if (err) {console.log(err);}}); } // 請求標題 let titleRequest = (url) => {return new Promise((resolve, reject) => {//采用http模塊向服務器發起一次get請求http.get(url, function (res) {let html = ''; //用來存儲請求網頁的整個html內容//監聽data事件,每次取一塊數據res.on('data', function (chunk) {html += iconv.decode(chunk, 'GBK');});//監聽end事件,如果整個網頁內容的html都獲取完畢,就執行回調函數res.on('end', function () {let $ = cheerio.load(html); //采用cheerio模塊解析html// 總的長度endNumber = $('#list a').length;let title = $('#list a').eq(number).text();let mainUrl = baseUrl + $('#list a').eq(number).attr('href');let item = {// 小說標題title: title,// 小說詳情mainUrl: mainUrl,//i是用來判斷獲取了多少篇文章i: number}// console.log(item); //打印新聞信息resolve(item);});}).on('error', function (err) {console.log(err);reject(err);});}); };// 請求內容 let mainRequest = (mainUrl) => {return new Promise((resolve, reject) => {//采用http模塊向服務器發起一次get請求http.get(mainUrl, function (res) {let html = ''; //用來存儲請求網頁的整個html內容//監聽data事件,每次取一塊數據res.on('data', function (chunk) {html += iconv.decode(chunk, 'GBK');});//監聽end事件,如果整個網頁內容的html都獲取完畢,就執行回調函數res.on('end', function () {let $ = cheerio.load(html); //采用cheerio模塊解析htmllet detail = $('#content').text().replace(/\s+/g,"\r\n\r\n    ");// console.log(detail); // 打印詳情resolve(detail);});}).on('error', function (err) {console.log(err);reject(err);});}); } // 開始執行 startRequest(url); 復制代碼::: hljs-center
2.8更新
:::
::: hljs-center
=====================================================================
:::
** 本來是獲取一次標題,然后在獲取一次內容,這樣每一章都要去請求兩次,所以導致速度比較慢。 現在修改為,標題就一次性全部獲取,保存起來,然后去在一次次去獲取內容,這樣標題請求一次就好了,省了一半的請求,速度能不快嘛。 直接貼關鍵代碼,剩下的自己去對比吧**
請求標題的時候,修改了一下
// 請求標題 let titleRequest = (url) => {return new Promise((resolve, reject) => {//采用http模塊向服務器發起一次get請求http.get(url, function (res) {let html = ''; //用來存儲請求網頁的整個html內容//監聽data事件,每次取一塊數據res.on('data', function (chunk) {html += iconv.decode(chunk, 'GBK');});let allData = [];//監聽end事件,如果整個網頁內容的html都獲取完畢,就執行回調函數res.on('end', function () {let $ = cheerio.load(html); //采用cheerio模塊解析html$('#list a').each(function(index, item){let title = $(this).text();let mainUrl = $(this).attr('href');let itemData = {// 小說標題title: title,// 小說詳情mainUrl: baseUrl + mainUrl,//i是用來判斷獲取了多少篇文章i: number};allData.push(itemData);});// console.log(allData); //打印新聞信息resolve(allData);});}).on('error', function (err) {console.log(err);reject(err);});}); }; 復制代碼然后是總的請求修改了一下
// 開始請求,并且寫入數據 let startSave = async function (){// 獲取所有標題以及內容的地址,整合成一個json,這樣標題獲取一次就好了,和上次比,少了好多好多請求。let urlArr = await titleRequest(url);for(let i = 0; i < urlArr.length; i++) {number++;console.log(`開始爬取 ${urlArr[i].title}`);// 開始獲取單章內容let mainDetail = await mainRequest(urlArr[i].mainUrl);console.log(`寫入 ${urlArr[i].title}`);await savedContent('./data/', `${number} ${urlArr[i].title}`, mainDetail);}console.log('===========================全部完成==========================='); }; 復制代碼這里就不上全部代碼了,可以去git庫看。
::: hljs-center
年輕就是折騰,來加我啊
:::
轉載于:https://juejin.im/post/5a9f967d6fb9a028ca528495
總結
以上是生活随笔為你收集整理的NodeJs ES6 写简单爬虫 爬小说网站《我当方士那些年》的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Simulink专题】Simulink
- 下一篇: 进程同步与异步概念