首頁 > web前端 > js教程 > 主體

Node.js 實作簡單小說爬蟲實例

高洛峰
發布: 2016-12-06 14:25:59
原創
1487 人瀏覽過

最近因為劇荒,老大追了愛奇藝的一部網劇,由丁墨的同名小說《美人為餡》改編,目前已經放出兩季,雖然整部劇槽點滿滿,但是老大看得不亦樂乎,並且在看完第二季之後跟我要小說資源,直接要奔原著去看結局……

隨手搜了下,都是在線資源,下載的話需要登錄,註冊登錄好麻煩,寫個爬蟲玩玩也好,於是動手用node 寫了一個,這裡做下筆記

工作流程

獲取URLs 列表(請求資源 request模組)

根據URLs 列表獲取相關頁面源碼(可能遇到相關頁源(頁面編碼問題,iconv-lite模組)

源碼解析,獲取小說資訊( cheerio模組)

保存小說資訊到Markdown 文件,並且加適當修飾以及章節資訊(寫文件fs、同步請求資源 sync-request 模組)

Markdown 轉PDF (使用Pandoc 或Chrome 的列印功能)

取得URLs

根據小說的導航頁,取得小說所有章節的URL,並以JSON 陣列的方式儲存。

首選透過 http.get() 方法取得頁面原始碼

取得到原始碼,列印發現中文亂碼,檢視發現 charset = 'gbk',需要進行轉碼

使用iconv-lite 模組進行轉碼,中文顯示正常顯示後來開始解析源碼,取得所需的URL,為了更方便地解析,需要引進 cheerio 模組,cheerio 可以理解為運行在後台的jQuery,用法與jQuery 也十分相似,熟悉jQuery 的同學可以很快的上手

將原始碼載入進 cheerio,分析了原始碼後得知所有章節資訊都存於被div 包裹的a 標籤中,透過 cheerio 取出符合條件的 a 標籤組,進行遍歷,取得章節的title 和URL,儲存為對象,存進數組,(因為連結中儲存的URL 不完整,所以儲存時需要補齊)

將物件陣列序列化,寫進 list.json 檔案

var http = require("http")
var fs = require("fs")
var cheerio = require("cheerio")
var iconv = require("iconv-lite")
var url = 'http://www.17fa.com/files/article/html/90/90747/index.html'
http.get(url, function(res) { //资源请求
  var chunks = []
  res.on('data', function(chunk) {
    chunks.push(chunk)
  })
  res.on('end', function() {
    var html = iconv.decode(Buffer.concat(chunks), 'gb2312') //转码操作
    var $ = cheerio.load(html, {
      decodeEntities: false
    })
    var content = $("tbody")
    var links = []
    $('div').children('a').each(function(i, elem) {
      var link = new Object()
      link.title = $(this).text()
      link.link = 'http://www.17fa.com/files/article/html/90/90747/' + $(this).attr('href') //补齐 URL 信息
      if (i > 5) {
        links.push(link)
      }
    })
    fs.writeFile("list.json", JSON.stringify(links), function(err) {
      if (!err) {
        console.log("写文件成功")
      }
    })
  }).on('error', function() {
    console.log("网页访问出错")
  })
})
登入後複製

   

獲取數據

有了URLs 列表,接下來的工作就很機械了,遍歷URLs 列表請求資源,獲取源碼,解析源碼,獲取小說,寫文件,但是,因為最終將所有的章節保存入一個文件,要確保章節的順序,因此寫文件需要同步操作,實際上,我在編碼的時候所有的操作都改成了同步方式

獲取源碼


通過解析讀取的list.json 文件,獲取到URLs 列表,遍歷列表獲取資源,因為需要確保章節的順序,所以這裡引進 sync-request 模組進行同步request 請求資源,請求資源後照例轉碼

[{
  "title": "3 法医司白",
  "link": "http://www.17fa.com/files/article/html/90/90747/16548771.html"
}, {
  "title": "4 第1个梦 ",
  "link": "http://www.17fa.com/files/article/html/90/90747/16548772.html"
}, {
  "title": "5 刑警韩沉 ",
  "link": "http://www.17fa.com/files/article/html/90/90747/16548773.html"
}, {
  "title": "6 最初之战",
  "link": "http://www.17fa.com/files/article/html/90/90747/16548774.html "
}]
登入後複製

   


還是透過 cheerio 模組取得小說內容,避免影響觀感,寫入作業之前去除內容中的html 標籤

var http = require("http")
var fs = require("fs")
var cheerio = require("cheerio")
var iconv = require("iconv-lite")
var request = require('sync-request')
var urlList = JSON.parse(fs.readFileSync('list.json', 'utf8'))
function getContent(chapter) {
  var res = request('GET',chapter.link)
  var html = iconv.decode(res.body, 'gb2312') //获取源码
}
for (let i = 0; i < urlList.length; i++) {
  getContent(urlList[i])
}
登入後複製

   

保存小說


寫作業也需要同步操作,因此使用了同步寫函數,因此使用了同步寫() 和同步新增函數 fs.appendFileSync(),第一次寫使用寫函數,之後的內容都是進行append 操作,為了改善閱讀體驗,每個章節前添加標題

也可以在內容前添加拍[TOC],作為導航連結

function getContent(chapter) {
  var res = request(&#39;GET&#39;,chapter.link)
  var html = iconv.decode(res.body, &#39;gb2312&#39;)
  var $ = cheerio.load(html, {
    decodeEntities: false
  })
  var content = ($("div#r1c").text()).replace(/\ /g, &#39;&#39;)
}
登入後複製

Markdown 轉PDF


我將小說保存在Markdown 文件中,為了提升閱讀體驗,可以將Markdown 文件轉換成PDF 文件,目前我較為喜歡的兩種方式,透過Chrome 的列印功能以及pandoc 轉換

Chrome 列印

Node.js 實作簡單小說爬蟲實例SublimeText 有個插件markdown preview ,可透過Alt + m 快鍵在Chrome 中預覽Markdown,在Chrome 頁面中按鍵選擇另存為PDF,簡單,粗暴,深得我心

打印效果:

pandoc 轉換
pandoc 是十分強大的文件格式轉換工具,可以將Markdown 文件轉換成多種格式,今晚在windows10下折騰了半天,總是檢索不到pdflatex,關於pandoc,後面會特別寫一篇總結。

PDF 已經發給老大了,現在正在看

關於python、node、爬蟲

Node.js 實作簡單小說爬蟲實例在之前很長的一段時間裡,很想用Python,很想寫爬蟲,更想用Python 寫爬蟲,甚至成為了心裡的一塊執念,隨著接觸的知識更全面,執念也逐漸淡去,少了很多“想”,遇事想著多去動手,實踐出真知。


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板