最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

node+experss實(shí)現(xiàn)爬取電影天堂爬蟲(chóng)

 更新時(shí)間:2016年11月20日 09:30:20   作者:xianyulaodi  
本文給大家分享的是node+experss制作爬蟲(chóng)的第二篇,我們來(lái)爬取電影天堂最新更新的電影迅雷下載鏈接,有需要的小伙伴可以參考下

上周寫(xiě)了一個(gè)node+experss的爬蟲(chóng)小入門(mén)。今天繼續(xù)來(lái)學(xué)習(xí)一下,寫(xiě)一個(gè)爬蟲(chóng)2.0版本。

這次我們不再爬博客園了,咋玩點(diǎn)新的,爬爬電影天堂。因?yàn)槊總€(gè)周末都會(huì)在電影天堂下載一部電影來(lái)看看。

talk is cheap,show me the code!

抓取頁(yè)面分析

我們的目標(biāo):

1、抓取電影天堂首頁(yè),獲取左側(cè)最新電影的169條鏈接

2、抓取169部新電影的迅雷下載鏈接,并且并發(fā)異步抓取。

具體分析如下:

1、我們不需要抓取迅雷的所有東西,只需要下載最新發(fā)布的電影即可,比如下面的左側(cè)欄。一共有170個(gè),除去第一個(gè)(因?yàn)榈谝粋€(gè)里面有200部電影),一共有169部電影。

2、除了抓取首頁(yè)的東西,我們還要抓取點(diǎn)進(jìn)去之后,每部電影的迅雷下載鏈接

環(huán)境搭建

1、需要的東西:node環(huán)境、express、cherrio 這三個(gè)都是上一篇文章有介紹的,所以這里不再做介紹:點(diǎn)擊查看

2、需要安裝的新東西:

superagent:

作用:跟request差不多,我們可以用它來(lái)獲取get/post等請(qǐng)求,并且可以設(shè)置相關(guān)的請(qǐng)求頭信息,相比較使用內(nèi)置的模塊,要簡(jiǎn)單很多。

用法:

var superagent = require('superagent');
superagent
.get('/some-url')
.end(function(err, res){
  // Do something 
});

superagent-charset:

作用:解決編碼問(wèn)題,因?yàn)殡娪疤焯玫木幋a是gb2312,爬取下來(lái)的中文會(huì)亂碼掉。

用法:

var superagent = require('superagent');
var charset = require('superagent-charset');
charset(superagent);

superagent
.get('/some-url')
.charset('gb2312') //這里設(shè)置編碼
.end(function(err, res){
  // Do something 
});

async:

作用:Async是一個(gè)流程控制工具包,提供了直接而強(qiáng)大的異步功能,在這里作為處理并發(fā)來(lái)調(diào)用。

用法:這里需要用到的是:async.mapLimit(arr, limit, iterator, callback)

mapLimit可以同時(shí)發(fā)起多個(gè)異步操作,然后一起等待callback的返回,返回一個(gè)就再發(fā)起下一個(gè)。

arr是一個(gè)數(shù)組,limit并發(fā)數(shù),將arr中的每一項(xiàng)依次拿給iterator去執(zhí)行,執(zhí)行結(jié)果傳給最后的callback

eventproxy:

作用:eventproxy 起到了計(jì)數(shù)器的作用,它來(lái)幫你管理到底異步操作是否完成,完成之后,它會(huì)自動(dòng)調(diào)用你提供的處理函數(shù),并將抓取到的數(shù)據(jù)當(dāng)參數(shù)傳過(guò)來(lái)。

例如我首先抓取到電影天堂首頁(yè)側(cè)欄的鏈接,才可以接著抓取鏈接里面的內(nèi)容。具體作用可以點(diǎn)這里

用法:

var ep = new EventProxy();
ep.after('got_file', files.length, function (list) {
 // 在所有文件的異步執(zhí)行結(jié)束后將被執(zhí)行 
 // 所有文件的內(nèi)容都存在list數(shù)組中 
});
for (var i = 0; i < files.length; i++) {
 fs.readFile(files[i], 'utf-8', function (err, content) {
  // 觸發(fā)結(jié)果事件 
  ep.emit('got_file', content);
 });
}
//注意got_file這兩個(gè)名字必須對(duì)應(yīng)

開(kāi)始爬蟲(chóng)

主要的程序在app.js這里,所以看的話可以主要看app.js即可

1、首先定義一些全局變量,該引入的庫(kù)引進(jìn)來(lái)

var cheerio = require('cheerio'); //可以像jquer一樣操作界面
var charset = require('superagent-charset'); //解決亂碼問(wèn)題:
var superagent = require('superagent'); //發(fā)起請(qǐng)求 
charset(superagent); 
var async = require('async'); //異步抓取
var express = require('express'); 
var eventproxy = require('eventproxy'); //流程控制
var ep = eventproxy();
var app = express();

var baseUrl = 'http://www.dytt8.net'; //迅雷首頁(yè)鏈接
var newMovieLinkArr=[]; //存放新電影的url
var errLength=[];   //統(tǒng)計(jì)出錯(cuò)的鏈接數(shù)
var highScoreMovieArr=[] //高評(píng)分電影

2、開(kāi)始爬取首頁(yè)迅雷首頁(yè):

//先抓取迅雷首頁(yè)
(function (page) {
  superagent
  .get(page)
  .charset('gb2312')
  .end(function (err, sres) {
    // 常規(guī)的錯(cuò)誤處理
    if (err) {
     console.log('抓取'+page+'這條信息的時(shí)候出錯(cuò)了')
      return next(err);
    }
    var $ = cheerio.load(sres.text);
    // 170條電影鏈接,注意去重
    getAllMovieLink($);
    highScoreMovie($);
    /*
    *流程控制語(yǔ)句
    *當(dāng)首頁(yè)左側(cè)的鏈接爬取完畢之后,我們就開(kāi)始爬取里面的詳情頁(yè)
    */
    ep.emit('get_topic_html', 'get '+page+' successful');
  });
})(baseUrl);

在這里,我們先抓取首頁(yè)的東西,把首頁(yè)抓取到的頁(yè)面內(nèi)容傳給 getAllMovieLink和highScoreMovie這兩個(gè)函數(shù)來(lái)處理,

getAllMovieLink獲取到了左側(cè)欄除了第1部的電影的169電影。

highScoreMovie為左側(cè)欄第一個(gè)鏈接,里面的都是評(píng)分比較高的電影。

上面的代碼中,我們弄了一個(gè)計(jì)數(shù)器,當(dāng)它執(zhí)行完之后,我們就可以執(zhí)行與‘get_topic_html‘名字對(duì)應(yīng)的流程了,從而可以保證在執(zhí)行完首頁(yè)的抓取工作之后,再執(zhí)行次級(jí)頁(yè)面的抓取工作。

ep.emit('get_topic_html', 'get '+page+' successful');

highScoreMovie方法如下,其實(shí)我們這里的作用不大,只是我統(tǒng)計(jì)一下高評(píng)分電影首頁(yè)的信息,懶的繼續(xù)抓取了

//評(píng)分8分以上影片 200余部!,這里只是統(tǒng)計(jì)數(shù)據(jù),不再進(jìn)行抓取
function highScoreMovie($){
  var url='http://www.dytt8.net'+$('.co_content2 ul a').eq(0).attr('href');
  console.log(url);
  superagent
  .get(url)
  .charset('gb2312')
  .end(function (err, sres) {
    // 常規(guī)的錯(cuò)誤處理
    if (err) {
      console.log('抓取'+url+'這條信息的時(shí)候出錯(cuò)了')
    }
    var $ = cheerio.load(sres.text);
    var elemP=$('#Zoom p');
    var elemA=$('#Zoom a');
    for (var k = 1; k < elemP.length; k++) {
      var Hurl=elemP.eq(k).find('a').text();
      if(highScoreMovieArr.indexOf(Hurl) ==-1){
        highScoreMovieArr.push(Hurl);
      };
    }
  });
}

3、分離出左側(cè)欄的信息,

如下圖,首頁(yè)中,詳情頁(yè)的鏈接都在這里$('.co_content2 ul a')。

因此我們將左側(cè)欄這里的詳情頁(yè)鏈接都遍歷出來(lái),保存在一個(gè)newMovieLinkArr這個(gè)數(shù)組里面。

getAllMovieLink方法如下:

// 獲取首頁(yè)中左側(cè)欄的所有鏈接
function getAllMovieLink($){
  var linkElem=$('.co_content2 ul a');
  for(var i=1;i<170;i++){
    var url='http://www.dytt8.net'+linkElem.eq(i).attr('href');
    // 注意去重
    if(newMovieLinkArr.indexOf(url) ==-1){
      newMovieLinkArr.push(url);
    };
  }
}

4、對(duì)獲取到的電影詳情頁(yè)進(jìn)行爬蟲(chóng),提取有用信息,比如電影的下載鏈接,這個(gè)是我們所關(guān)心的。

// 命令 ep 重復(fù)監(jiān)聽(tīng) emit事件(get_topic_html),當(dāng)get_topic_html爬取完畢之后執(zhí)行
ep.after('get_topic_html', 1, function (eps) {
  var concurrencyCount = 0;
  var num=-4; //因?yàn)槭?個(gè)并發(fā),所以需要減4

  // 利用callback函數(shù)將結(jié)果返回去,然后在結(jié)果中取出整個(gè)結(jié)果數(shù)組。
  var fetchUrl = function (myurl, callback) {
    var fetchStart = new Date().getTime();
    concurrencyCount++;
    num+=1
    console.log('現(xiàn)在的并發(fā)數(shù)是', concurrencyCount, ',正在抓取的是', myurl);
    superagent
    .get(myurl)
    .charset('gb2312') //解決編碼問(wèn)題
    .end(function (err, ssres) {

      if (err) {
        callback(err, myurl + ' error happened!');
        errLength.push(myurl);
        return next(err);
      }

      var time = new Date().getTime() - fetchStart;
      console.log('抓取 ' + myurl + ' 成功', ',耗時(shí)' + time + '毫秒');
      concurrencyCount--;

      var $ = cheerio.load(ssres.text);

      // 對(duì)獲取的結(jié)果進(jìn)行處理函數(shù)
      getDownloadLink($,function(obj){
        res.write('<br/>');
        res.write(num+'、電影名稱(chēng)--> '+obj.movieName);
        res.write('<br/>');
        res.write('迅雷下載鏈接--> '+obj.downLink);
        res.write('<br/>');
        res.write('詳情鏈接--> <a href='+myurl+' target="_blank">'+myurl+'<a/>');
        res.write('<br/>');
        res.write('<br/>');
      });
      var result = {
         movieLink: myurl
      };
      callback(null, result);
    });
  };

  // 控制最大并發(fā)數(shù)為5,在結(jié)果中取出callback返回來(lái)的整個(gè)結(jié)果數(shù)組。
  // mapLimit(arr, limit, iterator, [callback])
  async.mapLimit(newMovieLinkArr, 5, function (myurl, callback) {
    fetchUrl(myurl, callback);
  }, function (err, result) {
    // 爬蟲(chóng)結(jié)束后的回調(diào),可以做一些統(tǒng)計(jì)結(jié)果
    console.log('抓包結(jié)束,一共抓取了-->'+newMovieLinkArr.length+'條數(shù)據(jù)');
    console.log('出錯(cuò)-->'+errLength.length+'條數(shù)據(jù)');
    console.log('高評(píng)分電影:==》'+highScoreMovieArr.length);
    return false;
  });
  
});

首先是async.mapLimit對(duì)所有詳情頁(yè)做了一個(gè)并發(fā),并發(fā)數(shù)為5,然后再爬取詳情頁(yè),爬詳情頁(yè)的過(guò)程其實(shí)和爬首頁(yè)的過(guò)程是一樣的,所以這里不做過(guò)多的介紹,然后將有用的信息打印到頁(yè)面上。

5、執(zhí)行命令之后的圖如下所示:

瀏覽器界面:

這樣,我們爬蟲(chóng)的稍微升級(jí)版就就完成啦??赡芪恼聦?xiě)的不是很清楚,我已經(jīng)把代碼上傳到了github上,可以將代碼運(yùn)行一遍,這樣的話比較容易理解。后面如果有時(shí)間,可能會(huì)再搞一個(gè)爬蟲(chóng)的升級(jí)版本,比如將爬到的信息存入mongodb,然后再在另一個(gè)頁(yè)面展示。而爬蟲(chóng)的程序加個(gè)定時(shí)器,定時(shí)去抓取。

備注:如果運(yùn)行在瀏覽器中的中文亂碼的話,可以將谷歌的編碼設(shè)置為utf-8來(lái)解決;

代碼地址:https://github.com/xianyulaodi/mySpider2

有誤之處,歡迎指出

相關(guān)文章

  • Node js 中的 Multer中間件(文件上傳)

    Node js 中的 Multer中間件(文件上傳)

    本文介紹了Node.js中用于處理文件上傳的Multer中間件,詳細(xì)說(shuō)明了項(xiàng)目設(shè)置、安裝依賴(lài)的步驟,以及如何使用Multer上傳單個(gè)和多個(gè)文件,還介紹了DiskStorage引擎、其他配置選項(xiàng)和錯(cuò)誤處理方法,感興趣的朋友跟隨小編一起看看吧
    2025-03-03
  • node以及npm版本不對(duì)應(yīng)出錯(cuò)的完美解決方法

    node以及npm版本不對(duì)應(yīng)出錯(cuò)的完美解決方法

    最近項(xiàng)目用到了node和npm,查看一下當(dāng)前版本,發(fā)現(xiàn)有報(bào)錯(cuò),下面這篇文章主要給大家介紹了關(guān)于node以及npm版本不對(duì)應(yīng)出錯(cuò)的完美解決方法,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • 輕松創(chuàng)建nodejs服務(wù)器(5):事件處理程序

    輕松創(chuàng)建nodejs服務(wù)器(5):事件處理程序

    這篇文章主要介紹了輕松創(chuàng)建nodejs服務(wù)器(5):事件處理程序,本系列文章將一步一步創(chuàng)建一個(gè)完整的nodejs服務(wù)器,需要的朋友可以參考下
    2014-12-12
  • NodeJS讀取分析Nginx錯(cuò)誤日志的方法

    NodeJS讀取分析Nginx錯(cuò)誤日志的方法

    這篇文章主要介紹了NodeJS讀取分析Nginx錯(cuò)誤日志的相關(guān)知識(shí),本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-05-05
  • Nest.js中使用HTTP五種數(shù)據(jù)傳輸方式小結(jié)

    Nest.js中使用HTTP五種數(shù)據(jù)傳輸方式小結(jié)

    本文主要介紹了Nest.js中使用HTTP五種數(shù)據(jù)傳輸方式小結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • 詳解Node.js包的工程目錄與NPM包管理器的使用

    詳解Node.js包的工程目錄與NPM包管理器的使用

    這篇文章主要介紹了Node.js包的工程目錄與NPM包管理器的使用,可以幫助編程者更好地組織Node.js代碼文件,需要的朋友可以參考下
    2016-02-02
  • NodeJs?Express中間件超詳細(xì)講解

    NodeJs?Express中間件超詳細(xì)講解

    Express中間件本質(zhì)上就是一個(gè)function處理函數(shù),多個(gè)中間件之間,共享同一份req和res,我們就可以在上游的中間件中統(tǒng)一為req或者res對(duì)象添加自定義的屬性或方法,供下游的中間件或路由進(jìn)行使用,非常方便
    2022-08-08
  • 輕松創(chuàng)建nodejs服務(wù)器(1):一個(gè)簡(jiǎn)單nodejs服務(wù)器例子

    輕松創(chuàng)建nodejs服務(wù)器(1):一個(gè)簡(jiǎn)單nodejs服務(wù)器例子

    這篇文章主要介紹了一個(gè)簡(jiǎn)單nodejs服務(wù)器例子,本文實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的hello world例子,并展示如何運(yùn)行這個(gè)服務(wù)器,需要的朋友可以參考下
    2014-12-12
  • 詳解Node.js中的模塊化方法

    詳解Node.js中的模塊化方法

    這篇文章主要為大家介紹了Node.js的模塊化,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-01-01
  • 簡(jiǎn)單聊一聊Node.js參數(shù)max-old-space-size

    簡(jiǎn)單聊一聊Node.js參數(shù)max-old-space-size

    簡(jiǎn)單的說(shuō)Node.js就是運(yùn)行在服務(wù)端的JavaScript,下面這篇文章主要給大家介紹了關(guān)于Node.js參數(shù)max-old-space-size的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-01-01

最新評(píng)論

沂水县| 三江| 恩施市| 神农架林区| 信宜市| 微博| 兴文县| 华池县| 张掖市| 尼勒克县| 万州区| 罗定市| 建宁县| 宜川县| 横山县| 淳安县| 隆化县| 榕江县| 瑞金市| 华容县| 丰顺县| 突泉县| 奉贤区| 徐州市| 泰兴市| 资兴市| 贡山| 电白县| 无为县| 班戈县| 陇南市| 芜湖县| 宜春市| 顺义区| 天长市| 衡水市| 永川市| 惠安县| 曲松县| 偃师市| 文成县|