国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

使用node爬蟲,爬取指定排名網(wǎng)站的JS引用庫

Sleepy / 1396人閱讀

摘要:前期準(zhǔn)備本爬蟲將從網(wǎng)站爬取排名前幾的網(wǎng)站,具體前幾名可以具體設(shè)置,并分別爬取他們的主頁,檢查是否引用特定庫。正則獲取庫由于獲取頁面庫,首先需要獲取到的屬性,然后通過正則來實(shí)現(xiàn)字符串匹配。

前期準(zhǔn)備

本爬蟲將從網(wǎng)站爬取排名前幾的網(wǎng)站,具體前幾名可以具體設(shè)置,并分別爬取他們的主頁,檢查是否引用特定庫。

github地址

所用到的node主要模塊

express 不用多說

request http模塊

cheerio 運(yùn)行在服務(wù)器端的jQuery

node-inspector node調(diào)試模塊

node-dev 修改文件后自動(dòng)重啟app

關(guān)于調(diào)試Node

在任意一個(gè)文件夾,執(zhí)行node-inspector,通過打開特定頁面,在頁面上進(jìn)行調(diào)試,然后運(yùn)行app,使用node-dev app.js來自動(dòng)重啟應(yīng)用。

所碰到的問題 1. request請(qǐng)求多個(gè)頁面

由于請(qǐng)求是異步執(zhí)行的,和分別返回3個(gè)頁面的數(shù)據(jù),這里只爬取了50個(gè)網(wǎng)站,一個(gè)頁面有20個(gè),所以有3頁,通過循環(huán)里套request請(qǐng)求,來實(shí)現(xiàn)。

通過添加請(qǐng)求頭可以實(shí)現(xiàn)基本的反爬蟲

處理數(shù)據(jù)的方法都寫在analyData()里面,造成后面的數(shù)據(jù)重復(fù)存儲(chǔ)了,想了很久,才想到一個(gè)解決方法,后面會(huì)寫到是怎么解決的。

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. 多層回調(diào)

仔細(xì)觀察代碼,你會(huì)發(fā)現(xiàn),處理數(shù)據(jù)的方法使用了如下的多層回調(diào),也可以不使用回調(diào),寫在一個(gè)函數(shù)內(nèi)部;因?yàn)椋繉佣家褂蒙弦粚拥臄?shù)據(jù),造成了這樣的寫法。

function f1(data1){
    f2(data1);
}


function f2(data2){
    f3(data2);
}


function f3(data3){
    f4(data4);
}
3. 正則獲取JS庫

由于獲取頁面庫,首先需要獲取到script的src屬性,然后通過正則來實(shí)現(xiàn)字符串匹配。

獲取到的script可能是上面這樣的,由于庫名的命名真是各種各樣,后來想了一下,因?yàn)槲募怯?js結(jié)尾的,所以就以點(diǎn)號(hào)為結(jié)尾,然后把點(diǎn)號(hào)之前的字符截取下來,這樣獲得了庫名,代碼如下。

var reg = /[^/]+$/g;
var libName = jsLink.match(reg).join("");
var libFilter = libName.slice(0,libName.indexOf("."));
4.cheerio模塊獲取JS引用鏈接

這部分也花了一點(diǎn)時(shí)間,才搞定,cheerio獲取DOM的方法和jQuery是一樣的,需要對(duì)返回的DOM對(duì)象進(jìn)行查看,就可以看到對(duì)象里隱藏好深的href屬性,方法大同小異,你也可以使用其他選擇器,選擇到script標(biāo)簽

var $ = cheerio.load(body);
var scriptFile = $("script").toArray();


scriptFile.forEach(function(item,index){
    if (item.attribs.src != null) {
      obtainLibName(item.attribs.src,index);
}
5.存儲(chǔ)數(shù)據(jù)到數(shù)據(jù)庫

存儲(chǔ)數(shù)據(jù)的邏輯是先獲取所有的script信息,然后push到一個(gè)緩存數(shù)組,由于push后面,緊跟著存儲(chǔ)到數(shù)據(jù)庫的方法,這兩個(gè)方法都寫在循環(huán)里面的,例如爬取5個(gè)網(wǎng)站,每個(gè)網(wǎng)站存儲(chǔ)一次,后面也會(huì)跟著存儲(chǔ),造成數(shù)據(jù)重復(fù)存儲(chǔ)。解決方法是存儲(chǔ)數(shù)據(jù)的一般邏輯是先查,再存,這個(gè)查比較重要,查詢的方法也有多種,這里主要是根據(jù)庫名來查找唯一的數(shù)據(jù)對(duì)象,使用findOne方法。注意,由于node.js是異步執(zhí)行的,這里的閉包,每次只傳一個(gè)i值進(jìn)去,執(zhí)行存儲(chǔ)的操作。

// 將緩存數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫
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("保存數(shù)據(jù)出錯(cuò)" + err);
          });
        }

      })
    })(i)
  }
  console.log("一共存儲(chǔ)" + libObj.length + "條數(shù)據(jù)到數(shù)據(jù)庫");
}
6.分頁插件

本爬蟲前端使用了bootstrap.paginator插件,主要是前臺(tái)分頁,返回?cái)?shù)據(jù),根據(jù)點(diǎn)擊的頁數(shù),來顯示對(duì)應(yīng)的數(shù)據(jù),后期考慮使用AJAX請(qǐng)求的方式來實(shí)現(xiàn)翻頁的效果,這里的注意項(xiàng),主要是最后一頁的顯示,最好前面做個(gè)判斷,因?yàn)榉祷氐臄?shù)據(jù),不一定剛好是頁數(shù)的整數(shù)倍

function _paging(libObj) {
        var ele = $("#page");
        var pages = Math.ceil(libObj.length/20);
        console.log("總頁數(shù)" + 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("當(dāng)前選中第:" + 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 += "";
                    pHtml += (i+1) + "";
                    pHtml += libObj[i].name + "";
                    pHtml += libObj[i].libsNum + "";
                }
                libShow.html(pHtml);
            }
        })
      }
完整代碼 1. 前端
 
$(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("請(qǐng)輸入庫名~");
                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 += "";
                        libHtml += (i+1) + "";
                        libHtml += data[i].name + "";
                        libHtml += data[i].libsNum + "";
                    }
                    libShow.html(libHtml);
                }
            )
        });
      }

      function _showLibs(){
        show.click(function(){
            $.get(
                "/getLibs",
                {
                    rank: rank.val(),
                },
                function(data){
                    console.log("一共返回"+ data.length + "條數(shù)據(jù)");
                    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);// 點(diǎn)擊顯示按鈕,顯示前20項(xiàng)數(shù)據(jù)
                    _paging(data);
                }
            )
        });
      }

      //翻頁器
      function _paging(libObj) {
        var ele = $("#page");
        var pages = Math.ceil(libObj.length/20);
        console.log("總頁數(shù)" + 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("當(dāng)前選中第:" + 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 += "";
                    pHtml += (i+1) + "";
                    pHtml += libObj[i].name + "";
                    pHtml += libObj[i].libsNum + "";
                }
                libShow.html(pHtml);
            }
        })
      }

        function init() {
          _query();
         _showLibs();
        }

        return {
            init: init
        }

    })();

    checkLib.init();

})
2.后端路由
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("查詢出現(xiàn)錯(cuò)誤" + 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鏈接存為數(shù)組

    console.log("網(wǎng)站爬取中``")
    for (var i = 0; i < 10; i++) { // ***這里后面要改,默認(rèn)爬取前10名
        var url = sitesArr[i].attribs.href;
        sites.push(url);//保存網(wǎng)址,添加wwww前綴
    }
    console.log(sites);
    console.log("一共爬取" + sites.length +"個(gè)網(wǎng)站");
    console.log("存儲(chǔ)數(shù)據(jù)中...")

    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("出現(xiàn)錯(cuò)誤: "+err);
          var $ = cheerio.load(body);
          var scriptFile = $("script").toArray();
          callback(scriptFile,options.url);
        })
    })(j,storeLib)
  };

  function storeLib(scriptFile,url){
    flag++;// 是否存儲(chǔ)數(shù)據(jù)的標(biāo)志
    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和數(shù)據(jù)庫里存儲(chǔ)數(shù)據(jù),防止重復(fù)儲(chǔ)存
        // calcNum(src);//存儲(chǔ)數(shù)據(jù)到數(shù)據(jù)庫 // ***這里后面要改,默認(rèn)爬取前10名
        var libSrc = calcNum(src);
        store2db(libSrc);
      }
    })(flag,urls.length,src)
  } 
}// getScript END

// 將緩存數(shù)據(jù)存儲(chǔ)到數(shù)據(jù)庫
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("保存數(shù)據(jù)出錯(cuò)" + err);
          });
        }

      })
    })(i)
  }
  console.log("一共存儲(chǔ)" + libObj.length + "條數(shù)據(jù)到數(shù)據(jù)庫");
}
// 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;
后記

通過這個(gè)小爬蟲,學(xué)習(xí)到很多知識(shí),例如爬蟲的反爬蟲有哪些策越,意識(shí)到node.js的異步執(zhí)行特性,前后端是怎么進(jìn)行交互的。同時(shí),也意識(shí)到有一些方面的不足,后面還需要繼續(xù)改進(jìn),歡迎大家的相互交流。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/112289.html

相關(guān)文章

  • 使用node爬蟲爬取指定排名網(wǎng)站JS引用

    摘要:前期準(zhǔn)備本爬蟲將從網(wǎng)站爬取排名前幾的網(wǎng)站,具體前幾名可以具體設(shè)置,并分別爬取他們的主頁,檢查是否引用特定庫。正則獲取庫由于獲取頁面庫,首先需要獲取到的屬性,然后通過正則來實(shí)現(xiàn)字符串匹配。 前期準(zhǔn)備 本爬蟲將從網(wǎng)站爬取排名前幾的網(wǎng)站,具體前幾名可以具體設(shè)置,并分別爬取他們的主頁,檢查是否引用特定庫。 github地址 所用到的node主要模塊 express 不用多說 request ...

    helloworldcoding 評(píng)論0 收藏0
  • 使用node爬蟲爬取指定排名網(wǎng)站JS引用

    摘要:前期準(zhǔn)備本爬蟲將從網(wǎng)站爬取排名前幾的網(wǎng)站,具體前幾名可以具體設(shè)置,并分別爬取他們的主頁,檢查是否引用特定庫。正則獲取庫由于獲取頁面庫,首先需要獲取到的屬性,然后通過正則來實(shí)現(xiàn)字符串匹配。 前期準(zhǔn)備 本爬蟲將從網(wǎng)站爬取排名前幾的網(wǎng)站,具體前幾名可以具體設(shè)置,并分別爬取他們的主頁,檢查是否引用特定庫。 github地址 所用到的node主要模塊 express 不用多說 request ...

    Stardustsky 評(píng)論0 收藏0
  • Python爬蟲筆記1-爬蟲背景了解

    摘要:學(xué)習(xí)爬蟲的背景了解。但是搜索引擎蜘蛛的爬行是被輸入了一定的規(guī)則的,它需要遵從一些命令或文件的內(nèi)容,如標(biāo)注為的鏈接,或者是協(xié)議。不同領(lǐng)域不同背景的用戶往往具有不同的檢索目的和需求,搜索引擎無法提供針對(duì)具體某個(gè)用戶的搜索結(jié)果。 學(xué)習(xí)python爬蟲的背景了解。 大數(shù)據(jù)時(shí)代數(shù)據(jù)獲取方式 如今,人類社會(huì)已經(jīng)進(jìn)入了大數(shù)據(jù)時(shí)代,數(shù)據(jù)已經(jīng)成為必不可少的部分,可見數(shù)據(jù)的獲取非常重要,而數(shù)據(jù)的獲取的方式...

    oujie 評(píng)論0 收藏0
  • 一只node爬蟲升級(jí)打怪之路

    摘要:我是一個(gè)知乎輕微重度用戶,之前寫了一只爬蟲幫我爬取并分析它的數(shù)據(jù),我感覺這個(gè)過程還是挺有意思,因?yàn)檫@是一個(gè)不斷給自己創(chuàng)造問題又去解決問題的過程。所以這只爬蟲還有登陸知乎搜索題目的功能。 我一直覺得,爬蟲是許多web開發(fā)人員難以回避的點(diǎn)。我們也應(yīng)該或多或少的去接觸這方面,因?yàn)榭梢詮呐老x中學(xué)習(xí)到web開發(fā)中應(yīng)當(dāng)掌握的一些基本知識(shí)。而且,它還很有趣。 我是一個(gè)知乎輕微重度用戶,之前寫了一只爬...

    shiweifu 評(píng)論0 收藏0
  • Python_爬蟲基礎(chǔ)

    摘要:并不是所有爬蟲都遵守,一般只有大型搜索引擎爬蟲才會(huì)遵守。的端口號(hào)為的端口號(hào)為工作原理網(wǎng)絡(luò)爬蟲抓取過程可以理解為模擬瀏覽器操作的過程。表示服務(wù)器成功接收請(qǐng)求并已完成整個(gè)處理過程。 爬蟲概念 數(shù)據(jù)獲取的方式: 企業(yè)生產(chǎn)的用戶數(shù)據(jù):大型互聯(lián)網(wǎng)公司有海量用戶,所以他們積累數(shù)據(jù)有天然優(yōu)勢(shì)。有數(shù)據(jù)意識(shí)的中小型企業(yè),也開始積累的數(shù)據(jù)。 數(shù)據(jù)管理咨詢公司 政府/機(jī)構(gòu)提供的公開數(shù)據(jù) 第三方數(shù)據(jù)平臺(tái)購買...

    ixlei 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<