簡單高效的nodejs爬蟲模型

這篇文章講解一下yunshare項目的爬蟲模型。html

使用nodejs開發爬蟲很簡單,不須要相似python的scrapy這樣的爬蟲框架,只須要用request或者superagent這樣的http庫就能完成大部分的爬蟲工做了。node

使用nodejs開發爬蟲半年左右了,爬蟲能夠很簡單,也能夠很複雜。簡單的爬蟲定向爬取一個網站,可能有個幾萬或者幾十萬的頁面請求,複雜的爬蟲相似google bot這樣搜索引擎的蜘蛛爬蟲,要每時每刻爬取互聯網上最新的內容。python

通常的我的開發者都是用爬蟲定向爬取一些網站,而後提取一些結構化的數據,使用api接口獲取數據也能夠歸到這一類。若是想簡單的練習爬蟲技術,能夠嘗試爬取豆瓣電影數據和書籍數據的,使用api接口和爬取html頁面都能完成這個任務。git

爬蟲的說白了就是一個http客戶端,經過http協議和遠程http服務器通訊,獲取html頁面內容或者其餘的種子文件,pdf文件等等。和瀏覽器不一樣的一點就是爬蟲不會把抓取的內容渲染出來,而是解析頁面內容而後保存到數據庫裏面。github

在開始學習爬蟲的時候我考慮的是怎麼爬取html頁面內容,怎麼解析html頁面之間的連接規則,後來遇到了頁面編碼的問題。數據庫

統一utf8編碼

國內網站主要是使用html和gbk這兩種編碼方式,解決編碼有兩種思路,第一個是在獲取頁面內容的時候根據頁面的<meta charset='gbk'>編碼把內容統一轉碼成utf8的,由於nodejs字符串默認編碼就是utf8。json

這個方案充滿了不肯定性。api

問題1:不一樣網站的指定編碼的方式不同,除了前面提到的那種方式,還有<meta http-equiv="Content-Type" content="text/html; charset=gbk">這種方式指定編碼,這個問題還不是很大,不少的http工具庫都能正確的解析這兩種編碼,問題是還有不少網站沒有指定編碼,又或者指定的編碼和文件的實際編碼不一致(遇到過真實的案例)。promise

問題2:若是你把gbk編碼的html文件轉成utf8編碼保存到本地,用瀏覽器直接打開這個文件的時候會顯示亂碼,很是不利於開發過程當中的查找問題。瀏覽器

不轉碼html內容

既然前面的方案有這麼多的問題,剩下的方法就是把html內容直接按照原來的編碼保存到本地,而後解析的時候指定編碼。

這個方法有2個好處:一、簡化了爬蟲模型,二、能夠用瀏覽器打開html文件,不會亂碼。惟一的缺點是不一樣網站文件內容解析的時候彷佛須要指定編碼,對於小規模爬蟲這個問題其實影響不大。

統一爬蟲模型

前面的編碼方案解決了爬取不一樣網站html文件的編碼問題,咱們能夠用一個統一的爬蟲方法爬取不一樣網站的內容,那若是你想爬取非html內容呢?

是否是又要從新寫一個爬蟲方法,解決這個問題的方法就是http協議,假設咱們寫的這個爬蟲方法就是一個完整的http客戶端,那理論上這個客戶端是否是能根據Content-Typ獲取各類格式的文件。

那到底能不能用一個簡單的方法就能實現上述的功能呢?下面的方法就是我採用request寫的nodejs簡單高效的爬蟲模型。

function fetch(url) {
  console.log(`down ${url} started`);
  const deferred = Q.defer();
  const file = getfile(url);
  fs.ensureDirSync(path.dirname(file));
  const stream = request
    .get(url)
    .on('error', (err) => {
      deferred.reject(`down ${url}:${err}`);
    })
    .on('response', (res) => {
      if (res.statusCode !== 200) {
        deferred.reject(`down ${url}:${res.statusCode}`);
      } else {
        console.log(`down ${url}:${res.statusCode}`);
      }
    })
    .pipe(fs.createWriteStream(`${file}`));

  stream.on('finish', () => {
    deferred.resolve();
  });
  return deferred.promise;
}

這段代碼在yunshare/src/util/fetch.js裏面,固然這個方法不能單獨運行,可是關鍵的邏輯就是這麼簡單。

無論是什麼格式的http請求,json,html,torrent等都統一把返回的二進制格式文件保存到以md5(url)爲文件名的位置。上面的getfile就是用來獲取文件路徑的。

模型擴展

使用MD5散列仍是有發生衝突的風險的,若是你想要爬取上億的網頁,可能還須要對上面的模型進行擴展。一個簡單的思路就是把網頁路徑中的域名提取出來,不一樣網站的內容保存在對應的域文件夾下面。

其餘的相似的思路也行,須要注意的就是若是爬蟲保存文件和解析文件是分開的,你須要保證在解析文件的時候能用一樣的方法定位這個文件。共同的參數就是url,因此你生成文件名的時候不能用一些隨時間變化的參數。

最後,獻上第一個使用node全棧開發的網站:嗶哩搜索,目前索引百度網盤資源1000w條了。

相關文章
相關標籤/搜索