稍加改動,手把手寫一個acfun電影列表的爬蟲-基於node

最近有空又重新看了vue2.0的文檔,發現變動還是挺大的,多了虛擬dom,也像react有了對應JSX語法的render函數了,整個vue對象的生命週期也有了改動,而爲了迎合2.0的標準版腳手架而不是每次都用2.0的簡化版腳手架,我便決定開始慢慢的學習Node.js,其實之前也大概看過文檔,但是總覺得沒有需求,也不知從何下手,而現在個人發現語言和框架其實是爲了解決問題而誕生了,那麼學習其實也是在問題產生之後,需要解決問題而去主動學習。

我們最終的目的其實都是解決問題,這纔是關鍵。

學習node的過程中,不帶着需求學習更是茫然,看了文檔卻不知道去幹什麼~然而我突然很想寫爬蟲,總覺得很酷,所以毅然決定將這個需求帶進node,用node來實現就好,又可以滿足自己的需求又可以學習node,更是一舉兩得。

教程來自於一個簡單的爬蟲程序,是爬北大軟件學院的新聞網的一些信息和圖片,我已經收藏至我的收藏夾了,大家有興趣可以看看,在這裏我也把鏈接貼出來,由於是原創,所以不能隨便轉載
IT_石頭的csdn博客-手把手教你做爬蟲—基於NodeJs
坑爹的是,我爬了一次後,竟然就報超時了,刷新一下原網站,發現他們網站竟然崩了….有點逗了~

如果大家沒看原作者的教程,那麼請大家自行創建項目,去安裝必要的東西
npm install request 這是node的第三方工具,不是自帶的http的request,大家注意。

這裏先聲明一下,如果大家去爬的是完全同步請求的網站,記得要加載cheerio模塊,它可以使你在node上實現jquery的方法,方便你去爬取對應標籤,在原作者的教程中便是這個例子,大家自己去看看吧,A站由於電影列表有點特殊,是異步的get請求,所以這裏做法是有區別的,如果按照原作者的思路走,你爬出來的電影列表一定是空的,因爲請求地址已經不一樣了。

好了,爬之前我們先看看A站電影列表的請求格式
A站電影列表其中一頁

我們可以明確看到,請求是get的方式,而參數也很明顯爲channelId、sort、pageSize、pageNo,其中頁碼爲pageNo控制,所以後續我們的get請求去改變pageNo即可,主機名爲www.acfun.tv,請求地址爲主機名底下的list/getlist,如果爲post請求,那麼我們根據node的文檔將代碼中改爲http.request()的方式,methods方法爲post即可,大家自己去研究吧,這裏我就不說了~

好了,理解之後,於是我覺得去爬一些自己想爬的東西,所以就從經常上的網站開始吧,acfun的電影列表!show me my code

//我將其取名爲acfun-movie.js
var http = require('http');//加載http模塊
var fs = require('fs');    //加載文檔流模塊
var request = require('request');   //加載request模塊

//初始頁碼
var page = 1;
//初始url,經過多次切換頁碼,我們確定只有pageNo是改變的,其他都是既定的
var url = 'http://www.acfun.tv/list/getlist?channelId=96&sort=0&pageSize=20&pageNo='+page;

//封裝一層函數,我們優雅一點
function fetchPage(x){
    startRequest(x);
}

function startRequest(x){
    //利用http模塊向服務器發起一次get請求
    http.get(x,function(res){
        var allData = '';  //用於存儲請求網頁的整個內容
        res.setEncoding('utf-8');
        //監聽data事件,每次取一塊數據
        res.on('data',function(chunk){
            allData += chunk;
        });

        //監聽end事件,如果整個網頁內容的html都獲取完畢,就執行回調函數
        res.on('end',function(){
            //將取回的json格式字符串轉爲對象,並訪問數據數組
            var resData = JSON.parse(allData).data.data;

            console.log('正在爬取第'+page+'頁');
            saveContent(resData,page);//用於保存電影列表的內容
            saveImg(resData,page);    //用於保存電影列表的圖片

            //下一篇的url
            var nextLink = 'http://www.acfun.tv/list/getlist?channelId=96&sort=0&pageSize=20&pageNo='+page;

            //亮點:遞歸函數控制爬蟲的結束
            if(page<=10){
                fetchPage(nextLink);
            }
        });
    }).on('error',function(err){
        console.log(err);
    });
}

function saveContent(resData,page){
    var str = '';
    for(var i=0;i<resData.length;i++){
        //構造內容
        str += resData[i].title +'\r\n'+'鏈接:http://www.acfun.tv'+resData[i].link+'\r\n'+'up主'+resData[i].username+' 上傳時間:'+resData[i].contributeTimeFormat+' 被觀看次數:'+resData[i].viewCount+'\r\n\r\n'
    }
    //存儲文本內容-參數爲文件名,文件內容,文件格式,錯誤控制的回調函數
    fs.appendFile('./data/第'+page+'頁電影列表.txt',str,'utf-8',function(err){
        if(err){
            console.log(err);
        }
    });
}

function saveImg(resData,page){
    for(var i=0;i<resData.length;i++){
        //此正則爲中文取名,將名字'\'替換爲'/'否則讀取會被當做路徑格式讀取,現已註釋,因爲中文取名多容易發生錯誤
        // var img_title = resData[i].title;
        // img_title = img_title.replace(/\\/g,'/');
        //圖片名,對應頁碼與排位
        var img_title = page+'-'+(i+1);
        //圖片類型處理
        var img_type = resData[i].coverImage;
        img_type = img_type.slice(img_type.lastIndexOf('.'));
        //圖片請求路徑
        var img_src = resData[i].coverImage;
        console.log(img_src);

        //用request請求去驗證圖片超鏈接是否存在,這一步即使沒有也可以運行,但最好利用head請求去 請求頭部驗證超鏈接是否存在與被修改,以防萬一
        request.head(img_src,function(err,res,body){
            if(err){
                console.log(err)
            }
        });
        //request利用pipe流去存儲圖片,一定要寫錯誤控制,否則會報錯,未寫錯誤控制
       console.log(img_title+img_type);
    request(img_src).pipe(fs.createWriteStream('./image/'+img_title+img_type)).on('error',function(err){
            if(err){
                console.log(err);
            }
        });
        console.log(img_title+'Done');
    }
}
//執行函數
fetchPage(url);

最後在項目文件夾下運行node acfun-movie.js 跑起來即可,這裏就算完成了,希望大家不要用cv大法,畢竟只有自己打出來理解了纔是自己的東西~
有一些圖片的爬取會報錯:no such file or directory,沒有這個文件或這個目錄,其實是A站的問題,因爲。。。
這裏寫圖片描述

如你所見,圖片地址也是網絡請求,這裏我就沒處理了,因爲畢竟還是很少的~如果你有興趣就自己去處理下吧~

補上完成圖
存放內容與圖片的文件夾

內容

內容示例

部分圖片展示

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章