摘要:前期準備本爬蟲將從網站爬取排名前幾的網站,具體前幾名可以具體設置,并分別爬取他們的主頁,檢查是否引用特定庫。正則獲取庫由于獲取頁面庫,首先需要獲取到的屬性,然后通過正則來實現字符串匹配。
前期準備
本爬蟲將從網站爬取排名前幾的網站,具體前幾名可以具體設置,并分別爬取他們的主頁,檢查是否引用特定庫。
github地址
所用到的node主要模塊
express 不用多說
request http模塊
cheerio 運行在服務器端的jQuery
node-inspector node調試模塊
node-dev 修改文件后自動重啟app
關于調試Node在任意一個文件夾,執行node-inspector,通過打開特定頁面,在頁面上進行調試,然后運行app,使用node-dev app.js來自動重啟應用。
所碰到的問題 1. request請求多個頁面由于請求是異步執行的,和分別返回3個頁面的數據,這里只爬取了50個網站,一個頁面有20個,所以有3頁,通過循環里套request請求,來實現。
通過添加請求頭可以實現基本的反爬蟲
處理數據的方法都寫在analyData()里面,造成后面的數據重復存儲了,想了很久,才想到一個解決方法,后面會寫到是怎么解決的。
for (var i = 1; i < len+1; i++) { (function(i){ var options = { url: "http://www.alexa.cn/siterank/" + i, headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" } }; request(options, function (err, response, body) { analyData(body,rank); }) })(i) }2. 多層回調
仔細觀察代碼,你會發現,處理數據的方法使用了如下的多層回調,也可以不使用回調,寫在一個函數內部;因為,每層都要使用上一層的數據,造成了這樣的寫法。
function f1(data1){ f2(data1); } function f2(data2){ f3(data2); } function f3(data3){ f4(data4); }3. 正則獲取JS庫
由于獲取頁面庫,首先需要獲取到script的src屬性,然后通過正則來實現字符串匹配。
獲取到的script可能是上面這樣的,由于庫名的命名真是各種各樣,后來想了一下,因為文件名是用.js結尾的,所以就以點號為結尾,然后把點號之前的字符截取下來,這樣獲得了庫名,代碼如下。
var reg = /[^/]+$/g; var libName = jsLink.match(reg).join(""); var libFilter = libName.slice(0,libName.indexOf("."));4.cheerio模塊獲取JS引用鏈接
這部分也花了一點時間,才搞定,cheerio獲取DOM的方法和jQuery是一樣的,需要對返回的DOM對象進行查看,就可以看到對象里隱藏好深的href屬性,方法大同小異,你也可以使用其他選擇器,選擇到script標簽
var $ = cheerio.load(body); var scriptFile = $("script").toArray(); scriptFile.forEach(function(item,index){ if (item.attribs.src != null) { obtainLibName(item.attribs.src,index); }5.存儲數據到數據庫
存儲數據的邏輯是先獲取所有的script信息,然后push到一個緩存數組,由于push后面,緊跟著存儲到數據庫的方法,這兩個方法都寫在循環里面的,例如爬取5個網站,每個網站存儲一次,后面也會跟著存儲,造成數據重復存儲。解決方法是存儲數據的一般邏輯是先查,再存,這個查比較重要,查詢的方法也有多種,這里主要是根據庫名來查找唯一的數據對象,使用findOne方法。注意,由于node.js是異步執行的,這里的閉包,每次只傳一個i值進去,執行存儲的操作。
// 將緩存數據存儲到數據庫 function store2db(libObj){ console.log(libObj); for (var i = 0; i < libObj.length; i++) { (function(i){ var jsLib = new JsLib({ name: libObj[i].lib, libsNum: libObj[i].num }); JsLib.findOne({"name": libObj[i].lib},function(err,libDoc){ if(err) console.log(err); // console.log(libDoc) if (!libDoc){ jsLib.save(function(err,result){ if(err) console.log("保存數據出錯" + err); }); } }) })(i) } console.log("一共存儲" + libObj.length + "條數據到數據庫"); }6.分頁插件
本爬蟲前端使用了bootstrap.paginator插件,主要是前臺分頁,返回數據,根據點擊的頁數,來顯示對應的數據,后期考慮使用AJAX請求的方式來實現翻頁的效果,這里的注意項,主要是最后一頁的顯示,最好前面做個判斷,因為返回的數據,不一定剛好是頁數的整數倍
function _paging(libObj) { var ele = $("#page"); var pages = Math.ceil(libObj.length/20); console.log("總頁數" + pages); ele.bootstrapPaginator({ currentPage: 1, totalPages: pages, size:"normal", bootstrapMajorVersion: 3, alignment:"left", numberOfPages:pages, itemTexts: function (type, page, current) { switch (type) { case "first": return "首頁"; case "prev": return "上一頁"; case "next": return "下一頁"; case "last": return "末頁"; case "page": return page; } }, onPageClicked: function(event, originalEvent, type, page){ // console.log("當前選中第:" + page + "頁"); var pHtml = ""; var endPage; var startPage = (page-1) * 20; if (page < pages) { endPage = page * 20; }else{ endPage = libObj.length; } for (var i = startPage; i < endPage; i++) { pHtml += "完整代碼 1. 前端"; } libShow.html(pHtml); } }) } "; pHtml += (i+1) + " "; pHtml += libObj[i].name + " "; pHtml += libObj[i].libsNum + "
$(function () { var query = $(".query"), rank = $(".rank"), show = $(".show"), queryLib = $(".queryLib"), libShow = $("#libShow"), libName = $(".libName"), displayResult = $(".displayResult"); var checkLib = (function(){ function _query(){ query.click(function(){ $.post( "/query", { rank: rank.val(), }, function(data){ console.log(data); } ) }); queryLib.click(function(){ var inputLibName = libName.val(); if (inputLibName.length == 0) { alert("請輸入庫名~"); return; } $.post( "/queryLib", { libName: inputLibName, }, function(data){ if(data.length == 0){ alert("沒有查詢到名為" + inputLibName + "的庫"); libName.val(""); libName.focus(); libShow.html("") return; } var libHtml = ""; for (var i = 0; i < data.length; i++) { libHtml += "2.后端路由"; } libShow.html(libHtml); } ) }); } function _showLibs(){ show.click(function(){ $.get( "/getLibs", { rank: rank.val(), }, function(data){ console.log("一共返回"+ data.length + "條數據"); console.log(data) var libHtml = ""; for (var i = 0; i < 20; i++) { libHtml += " "; libHtml += (i+1) + " "; libHtml += data[i].name + " "; libHtml += data[i].libsNum + " "; } displayResult.show(); libShow.html(libHtml);// 點擊顯示按鈕,顯示前20項數據 _paging(data); } ) }); } //翻頁器 function _paging(libObj) { var ele = $("#page"); var pages = Math.ceil(libObj.length/20); console.log("總頁數" + pages); ele.bootstrapPaginator({ currentPage: 1, totalPages: pages, size:"normal", bootstrapMajorVersion: 3, alignment:"left", numberOfPages:pages, itemTexts: function (type, page, current) { switch (type) { case "first": return "首頁"; case "prev": return "上一頁"; case "next": return "下一頁"; case "last": return "末頁"; case "page": return page; } }, onPageClicked: function(event, originalEvent, type, page){ // console.log("當前選中第:" + page + "頁"); var pHtml = ""; var endPage; var startPage = (page-1) * 20; if (page < pages) { endPage = page * 20; }else{ endPage = libObj.length; } for (var i = startPage; i < endPage; i++) { pHtml += " "; libHtml += (i+1) + " "; libHtml += data[i].name + " "; libHtml += data[i].libsNum + " "; } libShow.html(pHtml); } }) } function init() { _query(); _showLibs(); } return { init: init } })(); checkLib.init(); }) "; pHtml += (i+1) + " "; pHtml += libObj[i].name + " "; pHtml += libObj[i].libsNum + "
var express = require("express"); var mongoose = require("mongoose"); var request = require("request"); var cheerio =require("cheerio"); var router = express.Router(); var JsLib = require("../model/jsLib") /* 顯示主頁 */ router.get("/", function(req, res, next) { res.render("index"); }); // 顯示庫 router.get("/getLibs",function(req,res,next){ JsLib.find({}) .sort({"libsNum": -1}) .exec(function(err,data){ res.json(data); }) }) // 庫的查詢 router.post("/queryLib",function(req,res,next){ var libName = req.body.libName; JsLib.find({ name: libName }).exec(function(err,data){ if (err) console.log("查詢出現錯誤" + err); res.json(data); }) }) router.post("/query",function(req,res,next) { var rank = req.body.rank; var len = Math.round(rank/20); for (var i = 1; i < len+1; i++) { (function(i){ var options = { url: "http://www.alexa.cn/siterank/" + i, headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" } }; request(options, function (err, response, body) { analyData(body,rank); }) })(i) } res.json("保存成功") }) var sites = []; var flag = 0; function analyData(data,rank) { if(data.indexOf("html") == -1) return false; var $ = cheerio.load(data);// 傳遞 HTML var sitesArr = $(".info-wrap .domain-link a").toArray();//將所有a鏈接存為數組 console.log("網站爬取中``") for (var i = 0; i < 10; i++) { // ***這里后面要改,默認爬取前10名 var url = sitesArr[i].attribs.href; sites.push(url);//保存網址,添加wwww前綴 } console.log(sites); console.log("一共爬取" + sites.length +"個網站"); console.log("存儲數據中...") getScript(sites); } // 獲取JS庫文件地址 function getScript(urls) { var scriptArr = []; var src = []; var jsSrc = []; for (var j = 0; j < urls.length; j++) { (function(i,callback){ var options = { url: urls[i], headers: { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36" } } request(options, function (err, res, body) { if(err) console.log("出現錯誤: "+err); var $ = cheerio.load(body); var scriptFile = $("script").toArray(); callback(scriptFile,options.url); }) })(j,storeLib) }; function storeLib(scriptFile,url){ flag++;// 是否存儲數據的標志 scriptFile.forEach(function(item,index){ if (item.attribs.src != null) { obtainLibName(item.attribs.src,index); } }) function obtainLibName(jsLink,i){ var reg = /[^/]+$/g; var libName = jsLink.match(reg).join(""); var libFilter = libName.slice(0,libName.indexOf(".")); src.push(libFilter); } // console.log(src.length); // console.log(calcNum(src).length) (function(len,urlLength,src){ // console.log("length is "+ len) if (len == 10 ) {// len長度為url的長度才向src和數據庫里存儲數據,防止重復儲存 // calcNum(src);//存儲數據到數據庫 // ***這里后面要改,默認爬取前10名 var libSrc = calcNum(src); store2db(libSrc); } })(flag,urls.length,src) } }// getScript END // 將緩存數據存儲到數據庫 function store2db(libObj){ console.log(libObj); for (var i = 0; i < libObj.length; i++) { (function(i){ var jsLib = new JsLib({ name: libObj[i].lib, libsNum: libObj[i].num }); JsLib.findOne({"name": libObj[i].lib},function(err,libDoc){ if(err) console.log(err); // console.log(libDoc) if (!libDoc){ jsLib.save(function(err,result){ if(err) console.log("保存數據出錯" + err); }); } }) })(i) } console.log("一共存儲" + libObj.length + "條數據到數據庫"); } // JS庫排序算法 function calcNum(arr){ var libObj = {}; var result = []; for (var i = 0, len = arr.length; i < len; i++) { if (libObj[arr[i]]) { libObj[arr[i]] ++; } else { libObj[arr[i]] = 1; } } for(var o in libObj){ result.push({ lib: o, num: libObj[o] }) } result.sort(function(a,b){ return b.num - a.num; }); return result; } module.exports = router;后記
通過這個小爬蟲,學習到很多知識,例如爬蟲的反爬蟲有哪些策越,意識到node.js的異步執行特性,前后端是怎么進行交互的。同時,也意識到有一些方面的不足,后面還需要繼續改進,歡迎大家的相互交流。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/84284.html
摘要:前期準備本爬蟲將從網站爬取排名前幾的網站,具體前幾名可以具體設置,并分別爬取他們的主頁,檢查是否引用特定庫。正則獲取庫由于獲取頁面庫,首先需要獲取到的屬性,然后通過正則來實現字符串匹配。 前期準備 本爬蟲將從網站爬取排名前幾的網站,具體前幾名可以具體設置,并分別爬取他們的主頁,檢查是否引用特定庫。 github地址 所用到的node主要模塊 express 不用多說 request ...
摘要:前期準備本爬蟲將從網站爬取排名前幾的網站,具體前幾名可以具體設置,并分別爬取他們的主頁,檢查是否引用特定庫。正則獲取庫由于獲取頁面庫,首先需要獲取到的屬性,然后通過正則來實現字符串匹配。 前期準備 本爬蟲將從網站爬取排名前幾的網站,具體前幾名可以具體設置,并分別爬取他們的主頁,檢查是否引用特定庫。 github地址 所用到的node主要模塊 express 不用多說 request ...
摘要:學習爬蟲的背景了解。但是搜索引擎蜘蛛的爬行是被輸入了一定的規則的,它需要遵從一些命令或文件的內容,如標注為的鏈接,或者是協議。不同領域不同背景的用戶往往具有不同的檢索目的和需求,搜索引擎無法提供針對具體某個用戶的搜索結果。 學習python爬蟲的背景了解。 大數據時代數據獲取方式 如今,人類社會已經進入了大數據時代,數據已經成為必不可少的部分,可見數據的獲取非常重要,而數據的獲取的方式...
摘要:我是一個知乎輕微重度用戶,之前寫了一只爬蟲幫我爬取并分析它的數據,我感覺這個過程還是挺有意思,因為這是一個不斷給自己創造問題又去解決問題的過程。所以這只爬蟲還有登陸知乎搜索題目的功能。 我一直覺得,爬蟲是許多web開發人員難以回避的點。我們也應該或多或少的去接觸這方面,因為可以從爬蟲中學習到web開發中應當掌握的一些基本知識。而且,它還很有趣。 我是一個知乎輕微重度用戶,之前寫了一只爬...
摘要:并不是所有爬蟲都遵守,一般只有大型搜索引擎爬蟲才會遵守。的端口號為的端口號為工作原理網絡爬蟲抓取過程可以理解為模擬瀏覽器操作的過程。表示服務器成功接收請求并已完成整個處理過程。 爬蟲概念 數據獲取的方式: 企業生產的用戶數據:大型互聯網公司有海量用戶,所以他們積累數據有天然優勢。有數據意識的中小型企業,也開始積累的數據。 數據管理咨詢公司 政府/機構提供的公開數據 第三方數據平臺購買...
閱讀 1387·2021-10-14 09:43
閱讀 4235·2021-09-27 13:57
閱讀 4566·2021-09-22 15:54
閱讀 2560·2021-09-22 10:54
閱讀 2376·2021-09-22 10:02
閱讀 2117·2021-08-27 13:11
閱讀 876·2019-08-29 18:44
閱讀 1648·2019-08-29 15:20