從0到1學習node之簡易的網路爬蟲

2022-01-19 09:31:34 字數 4333 閱讀 2398

我們這節的目標是學習完本節課程後,能進行網頁簡單的分析與抓取,對抓取到的資訊進行輸出和文字儲存。

爬蟲的思路很簡單:

確定要抓取的url;

對url進行抓取,獲取網頁內容;

對內容進行分析並儲存;

重複第1步

總索引:

從0到1學習node(一)之模組規範

從0到1學習node(二)之搭建http伺服器

從0到1學習node(三)之檔案操作

從0到1學習node(四)之簡易的網路爬蟲

從0到1學習node(五)之mysql資料庫的操作

在這節裡做爬蟲,我們使用到了兩個重要的模組:

說是hello world,其實首先開始的是最簡單的抓取。我們就以cnode**為例(這個**的特點是:

**如下:

var request = require('request'),

cheerio = require('cheerio');

request('', function(err, response, body)

});

這樣的一段**就實現了乙個簡單的網路爬蟲,爬取到原始碼後,再對原始碼進行拆解分析,比如我們要獲取首頁中第1頁的 問題標題,作者,跳轉鏈結,點選數量,回覆數量。通過chrome,我們可以得到這樣的結構:

每個div[.cell]是乙個題目完整的單元,在這裡面,乙個單元暫時稱為$item

因此,迴圈div[.cell],就可以獲取到我們想要的資訊了:

request('?_t='+date.now(), function(err, response, body))

});// console.log( json.stringify(data, ' ', 4) );

console.log(data);

}});// 刪除字串左右兩端的空格

function trim(str)

上面我們只爬取了乙個頁面,怎麼在乙個程式裡爬取多個頁面呢?還是以cnode**為例,剛才只是爬取了第1頁的資料,這裡我們想請求它前6頁的資料(別同時抓太多的頁面,會被封ip的)。每個頁面的結構是一樣的,我們只需要修改url位址即可。

2.1 同時抓取多個頁面

首先把request請求封裝為乙個方法,方便進行呼叫,若還是使用console.log方法的話,會把6頁的資料都輸出到控制台,看起來很不方便。這裡我們就使用到了上節檔案操作內容,引入fs模組,將獲取到的內容寫入到檔案中,然後新建的檔案放到file目錄下(需手動建立file目錄):

// 把page作為引數傳遞進去,然後呼叫request進行抓取

function getdata(page))

});// console.log( json.stringify(data, ' ', 4) );

// console.log(data);

var filename = './file/cnode_'+page+'.txt';

fs.writefile(filename, json.stringify(data, ' ', 4), function())

}});

}

page=2,我們只需要修改page的值即可:

var max = 6;

for(var i=1; i<=max; i++)

$ node test.js

開始請求...

?tab=all&page=1: 279ms

./file/cnode_1.txt 寫入成功

?tab=all&page=3: 372ms

./file/cnode_3.txt 寫入成功

?tab=all&page=2: 489ms

./file/cnode_2.txt 寫入成功

?tab=all&page=4: 601ms

./file/cnode_4.txt 寫入成功

?tab=all&page=5: 715ms

./file/cnode_5.txt 寫入成功

?tab=all&page=6: 819ms

./file/cnode_6.txt 寫入成功

我們在file目錄下就能看到輸出的6個檔案了。

2.2 控制同時請求的數量

我們在使用for迴圈後,會同時發起所有的請求,如果我們同時去請求100、200、500個頁面呢,會造成短時間內對伺服器發起大量的請求,最後就是被封ip。這裡我寫了乙個排程方法,每次同時最多只能發起5個請求,上乙個請求完成後,再從佇列中取出乙個進行請求。

/*

@param data 需要請求的鏈結的集合

@param max num 最多同時請求的數量

*/function dispatch(data, max)

var surl = _dataobj.shift();

_cur++;

_callback(surl);}}

this.start = function(callback),

this.call = function()

}}var dis = new dispatch(urls, max);

dis.start(getdata);

然後在 getdata 中,寫入檔案的後面,進行dis的**呼叫:

var filename = './file/cnode_'+page+'.txt';

fs.writefile(filename, json.stringify(data, ' ', 4), function())

dis.call();

這樣就實現了非同步呼叫時控制同時請求的數量。

使用cookie。 使用者登入後,都會在cookie中記錄下使用者的一些資訊,我們在抓取一些頁面,帶上這些cookie,伺服器就會認為我們處於登入狀態,程式就能抓取到我們想要的資訊。

先在瀏覽器上登入我們的帳號,然後在console中使用document.domain獲取到所有cookie的字串,複製到下方程式的cookie處(如果你知道哪些cookie不需要,可以剔除掉)。

request(

}, function(error, response, body)

})

同時在request中,還可以設定referer,比如有的介面或者其他資料,設定了referer的限制,必須在某個網域名稱下才能訪問。那麼在request中,就可以設定referer來進行偽造。

頁面中的文字內容可以提煉後儲存到文字或者資料庫中,那麼怎麼儲存到本地呢。

可以使用request中的pipe方法輸出到檔案流中,然後使用fs.createwritestream輸出為。

這裡我們把儲存到以日期建立的目錄中,mkdirp可一次性建立多級目錄(./img/2017/01/22)。儲存的名稱,可以使用原名稱,也可以根據自己的規則進行命名。

var request = require('request'),

cheerio = require('cheerio'),

fs = require('fs'),

path = require('path'), // 用於分析的名稱或者字尾名

mkdirp = require('mkdirp'); // 用於建立多級目錄

var date = new date(),

year = date.getfullyear(),

month = date.getmonth()+1,

month = ('00'+month).slice(-2), // 新增前置0

day = date.getdate(),

day = ('00'+day).slice(-2), // 新增前置0

dir = './img/'+year+'/'+month+'/'+day+'/';

// 根據日期建立目錄 ./img/2017/01/22/

var stats = fs.statsync(dir);

if( stats.isdirectory() )else)

}request(, function(err, response, body))

}});// 儲存

var download = function(imgurl, filename));

}

我們這裡只是寫了乙個簡單的爬蟲,針對更複雜的功能,則需要更複雜的演算法的來控制了。還有如何抓取ajax的資料,我們會在後面進行講解。

從0到1學習記錄

競爭會讓你把注意力都放在競爭對手身上,忽視了自己的發展。競爭會造成非常低水平的重複和跟風。不存在完美的市場均衡,在經濟理論之外的現實世界裡,每個企業的成功,恰恰是因為它打破了均衡,它做到了其他企業不能做的事情,也就是從0到1的事情,而不是它跟其他企業做一樣的事兒。谷歌把自己定義成什麼,取決於什麼能給...

Python從0到1之異常

當檢測到錯誤時,直譯器無法繼續執行了,反而出現了一些錯誤提示,就是異常 try 可能發生錯誤的 except 如果出現異常執行的 try f open test.txt r except f open test.txt w try 1 0except zerodivisionerror print ...

專利工作之 從0到1

最初接觸專利,是在2001 2004年為華為總專案期間,那是自己是發明人。歷史總有巧合,從15年開始負責集團公司的專利工作,在此之前幾乎沒有專門的組織負責,算是從零起步。最開始想的很簡單,就是我已宣布,大家都覺得是個好事兒,又提公升公司品牌度,又提公升發明人個人品牌度,新業務研發領域的專利申請應該是...