国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > JavaScript > 正文

node+experss實現爬取電影天堂爬蟲

2019-11-19 18:55:15
字體:
來源:轉載
供稿:網友

上周寫了一個node+experss的爬蟲小入門。今天繼續來學習一下,寫一個爬蟲2.0版本。

這次我們不再爬博客園了,咋玩點新的,爬爬電影天堂。因為每個周末都會在電影天堂下載一部電影來看看。

talk is cheap,show me the code!

抓取頁面分析

我們的目標:

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

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

具體分析如下:

1、我們不需要抓取迅雷的所有東西,只需要下載最新發布的電影即可,比如下面的左側欄。一共有170個,除去第一個(因為第一個里面有200部電影),一共有169部電影。

2、除了抓取首頁的東西,我們還要抓取點進去之后,每部電影的迅雷下載鏈接

環境搭建

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

2、需要安裝的新東西:

superagent:

作用:跟request差不多,我們可以用它來獲取get/post等請求,并且可以設置相關的請求頭信息,相比較使用內置的模塊,要簡單很多。

用法:

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

superagent-charset:

作用:解決編碼問題,因為電影天堂的編碼是gb2312,爬取下來的中文會亂碼掉。

用法:

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

async:

作用:Async是一個流程控制工具包,提供了直接而強大的異步功能,在這里作為處理并發來調用。

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

mapLimit可以同時發起多個異步操作,然后一起等待callback的返回,返回一個就再發起下一個。

arr是一個數組,limit并發數,將arr中的每一項依次拿給iterator去執行,執行結果傳給最后的callback

eventproxy:

作用:eventproxy 起到了計數器的作用,它來幫你管理到底異步操作是否完成,完成之后,它會自動調用你提供的處理函數,并將抓取到的數據當參數傳過來。

例如我首先抓取到電影天堂首頁側欄的鏈接,才可以接著抓取鏈接里面的內容。具體作用可以點這里

用法:

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

開始爬蟲

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

1、首先定義一些全局變量,該引入的庫引進來

var cheerio = require('cheerio'); //可以像jquer一樣操作界面var charset = require('superagent-charset'); //解決亂碼問題:var superagent = require('superagent'); //發起請求 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'; //迅雷首頁鏈接var newMovieLinkArr=[]; //存放新電影的urlvar errLength=[];   //統計出錯的鏈接數var highScoreMovieArr=[] //高評分電影

2、開始爬取首頁迅雷首頁:

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

在這里,我們先抓取首頁的東西,把首頁抓取到的頁面內容傳給 getAllMovieLink和highScoreMovie這兩個函數來處理,

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

highScoreMovie為左側欄第一個鏈接,里面的都是評分比較高的電影。

上面的代碼中,我們弄了一個計數器,當它執行完之后,我們就可以執行與‘get_topic_html‘名字對應的流程了,從而可以保證在執行完首頁的抓取工作之后,再執行次級頁面的抓取工作。

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

highScoreMovie方法如下,其實我們這里的作用不大,只是我統計一下高評分電影首頁的信息,懶的繼續抓取了

//評分8分以上影片 200余部!,這里只是統計數據,不再進行抓取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) {    // 常規的錯誤處理    if (err) {      console.log('抓取'+url+'這條信息的時候出錯了')    }    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、分離出左側欄的信息,

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

因此我們將左側欄這里的詳情頁鏈接都遍歷出來,保存在一個newMovieLinkArr這個數組里面。

getAllMovieLink方法如下:

// 獲取首頁中左側欄的所有鏈接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、對獲取到的電影詳情頁進行爬蟲,提取有用信息,比如電影的下載鏈接,這個是我們所關心的。

// 命令 ep 重復監聽 emit事件(get_topic_html),當get_topic_html爬取完畢之后執行ep.after('get_topic_html', 1, function (eps) {  var concurrencyCount = 0;  var num=-4; //因為是5個并發,所以需要減4  // 利用callback函數將結果返回去,然后在結果中取出整個結果數組。  var fetchUrl = function (myurl, callback) {    var fetchStart = new Date().getTime();    concurrencyCount++;    num+=1    console.log('現在的并發數是', concurrencyCount, ',正在抓取的是', myurl);    superagent    .get(myurl)    .charset('gb2312') //解決編碼問題    .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 + ' 成功', ',耗時' + time + '毫秒');      concurrencyCount--;      var $ = cheerio.load(ssres.text);      // 對獲取的結果進行處理函數      getDownloadLink($,function(obj){        res.write('<br/>');        res.write(num+'、電影名稱--> '+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);    });  };  // 控制最大并發數為5,在結果中取出callback返回來的整個結果數組。  // mapLimit(arr, limit, iterator, [callback])  async.mapLimit(newMovieLinkArr, 5, function (myurl, callback) {    fetchUrl(myurl, callback);  }, function (err, result) {    // 爬蟲結束后的回調,可以做一些統計結果    console.log('抓包結束,一共抓取了-->'+newMovieLinkArr.length+'條數據');    console.log('出錯-->'+errLength.length+'條數據');    console.log('高評分電影:==》'+highScoreMovieArr.length);    return false;  });  });

首先是async.mapLimit對所有詳情頁做了一個并發,并發數為5,然后再爬取詳情頁,爬詳情頁的過程其實和爬首頁的過程是一樣的,所以這里不做過多的介紹,然后將有用的信息打印到頁面上。

5、執行命令之后的圖如下所示:

瀏覽器界面:

這樣,我們爬蟲的稍微升級版就就完成啦。可能文章寫的不是很清楚,我已經把代碼上傳到了github上,可以將代碼運行一遍,這樣的話比較容易理解。后面如果有時間,可能會再搞一個爬蟲的升級版本,比如將爬到的信息存入mongodb,然后再在另一個頁面展示。而爬蟲的程序加個定時器,定時去抓取。

備注:如果運行在瀏覽器中的中文亂碼的話,可以將谷歌的編碼設置為utf-8來解決;

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

有誤之處,歡迎指出

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 辉县市| 大城县| 巨鹿县| 无为县| 渭源县| 石楼县| 曲周县| 兴安盟| 淅川县| 宁夏| 革吉县| 临清市| 永德县| 新密市| 祁门县| 吴川市| 博爱县| 鸡西市| 图木舒克市| 南汇区| 左云县| 石棉县| 宁波市| 谢通门县| 柘荣县| 蒲江县| 安平县| 通河县| 义马市| 长兴县| 荆州市| 怀宁县| 松滋市| 阜城县| 达孜县| 抚松县| 南丹县| 会宁县| 竹北市| 沂南县| 石屏县|