欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Node.js環(huán)境下編寫爬蟲爬取維基百科內(nèi)容的實(shí)例分享

 更新時(shí)間:2016年06月12日 18:46:36   作者:zhoutk  
WikiPedia平時(shí)在國(guó)內(nèi)不大好訪問-- 所以用爬蟲一次性把要看的東西都爬下來(lái)保存慢慢看還是比較好的XD 這里我們就來(lái)看一下Node.js環(huán)境下編寫爬蟲爬取維基百科內(nèi)容的實(shí)例分享

基本思路
思路一(origin:master):從維基百科的某個(gè)分類(比如:航空母艦(key))頁(yè)面開始,找出鏈接的title屬性中包含key(航空母艦)的所有目標(biāo),加入到待抓取隊(duì)列中。這樣,抓一個(gè)頁(yè)面的代碼及其圖片的同時(shí),也獲取這個(gè)網(wǎng)頁(yè)上所有與key相關(guān)的其它網(wǎng)頁(yè)的地址,采取一個(gè)類廣度優(yōu)先遍歷的算法來(lái)完成此任務(wù)。
思路二(origin:cat):按分類進(jìn)行抓取。注意到,維基百科上,分類都以Category:開頭,由于維基百科有很好的文檔結(jié)構(gòu),很容易從任一個(gè)分類,開始,一直把其下的所有分類全都抓取下來(lái)。這個(gè)算法對(duì)分類頁(yè)面,提取子分類,且并行抓取其下所有頁(yè)面,速度快,可以把分類結(jié)構(gòu)保存下來(lái),但其實(shí)有很多的重復(fù)頁(yè)面,不過(guò)這個(gè)可以后期寫個(gè)腳本就能很容易的處理。

庫(kù)的選擇
開始想用jsdom,雖然感覺它功能強(qiáng)大,但也比較“重”,最要命的是說(shuō)明文檔不夠好,只說(shuō)了它的優(yōu)勢(shì),沒一個(gè)全面的說(shuō)明。因此,換成cheerio,輕量級(jí),功能比較全,至少文檔一看就能有一個(gè)整體概念。其實(shí)做到后來(lái),才發(fā)現(xiàn)根本不需要庫(kù),用正則表達(dá)式就能搞定一切!用庫(kù)只是少寫了一點(diǎn)正則而矣。

關(guān)鍵點(diǎn)
全局變量設(shè)定:

var regKey = ['航空母艦','航空母艦','航母'];  //鏈接中若包含此中關(guān)鍵詞,即為目標(biāo)
var allKeys = [];              //鏈接的title,也是頁(yè)面標(biāo)識(shí),避免重復(fù)抓取
var keys = ['Category:%E8%88%AA%E7%A9%BA%E6%AF%8D%E8%88%B0'];  //等待隊(duì)列,起始頁(yè)

圖片下載
使用request庫(kù)的流式操作,讓每一個(gè)下載操作形成閉包。注意異步操作可能帶來(lái)的副作用。另外,圖片名字要重新設(shè)定,開始我取原名,不知道為什么,有的圖明明存在,就是顯示不出來(lái);并且要把srcset屬性清理掉,不然本面顯示不出來(lái)。

$ = cheer.load(downHtml);
 var rsHtml = $.html();
 var imgs = $('#bodyContent .image');    //圖片都由這個(gè)樣式修飾
 for(img in imgs){
  if(typeof imgs[img].attribs === 'undefined' || typeof imgs[img].attribs.href === 'undefined')
   {continue;}  //結(jié)構(gòu)為鏈接下的圖片,鏈接不存在,跳過(guò)
  else
   {
    var picUrl = imgs[img].children[0].attribs.src;  //圖片地址
    var dirs = picUrl.split('.');
    var filename = baseDir+uuid.v1()+'.'+dirs[dirs.length -1];  //重新命名

    request("https:"+picUrl).pipe(fs.createWriteStream('pages/'+filename));  //下載

    rsHtml = rsHtml.replace(picUrl,filename);  //換成本地路徑
    // console.log(picUrl);
   }
 }

廣度優(yōu)先遍歷
開始沒能完全理解異步的概念,以循環(huán)方式來(lái)做,以為使用了Promise,就已經(jīng)全轉(zhuǎn)化為同步了,但其實(shí)只是能保證交給promise的操作會(huì)有序進(jìn)行,并不能讓這些操作與其它的操作有序化!如,下面的代碼就是不正確的。

var keys = ['航空母艦'];
var key = keys.shift();
while(key){
 data.get({
  url:encodeURI(key),
  qs:null
 }).then(function(downHtml){
    ...
    keys.push(key);        //(1)
  }
 });
key = keys.shift();          //(2)
}

上面的操作看試很正常,但其實(shí)(2)會(huì)在(1)之間被運(yùn)行!哪怎么辦?
我使用遞歸來(lái)解決這個(gè)問題。如下示例代碼:

var key = keys.shift();
(function doNext(key){
 data.get({
  url:key,
  qs:null
 }).then(function(downHtml){
  ...
  keys.push(href);
  ...
  key = keys.shift();
  if(key){
   doNext(key);
  }else{
   console.log('抓取任務(wù)順利完成。')
  }
 })
})(key);

正則清理
使用正則表達(dá)式清理無(wú)用的頁(yè)面代碼,因?yàn)橛泻芏嗄J叫枰幚?,寫了一個(gè)循環(huán)統(tǒng)一處理。

var regs = [/<link rel=\"stylesheet\" href=\"?[^\"]*\">/g,
  /<script>?[^<]*<\/script>/g,
 /<style>?[^<]*<\/style>/g,
 /<a ?[^>]*>/g,
 /<\/a>/g,
 /srcset=(\"?[^\"]*\")/g
 ]
 regs.forEach(function(rs){
  var mactches = rsHtml.match(rs);
  for (var i=0;i < mactches.length ; i++)
  {
   rsHtml = rsHtml.replace(mactches[i],mactches[i].indexOf('stylesheet')>-1?'<link rel="stylesheet" href="wiki'+(i+1)+'.css"':'');
  }
 })

運(yùn)行效果
上維基中文是需要FQ的,試運(yùn)行了一下,抓取 航空母艦 分類,運(yùn)行過(guò)程中,發(fā)現(xiàn)了三百左右的相關(guān)鏈接(包括分類頁(yè)面,這些頁(yè)面我是只取有效鏈接,不下載),最終正確的下載了209個(gè),手工測(cè)試了一些出錯(cuò)鏈接,發(fā)現(xiàn)都為無(wú)效鏈接,顯示該詞條還未建立,整個(gè)過(guò)程大概花了不到十五分鐘,壓縮后近三十M,感覺效果還不錯(cuò)。

源代碼
https://github.com/zhoutk/wikiSpider
小結(jié)
到昨晚基本完成任務(wù),思路一能夠抓取內(nèi)容比較準(zhǔn)確的頁(yè)面,而且頁(yè)面不重復(fù),但抓取效率不高,分類信息無(wú)法準(zhǔn)確獲得;思路二能夠按維基百科的分類,自動(dòng)抓取并分門別類的把文件存儲(chǔ)到本地,效率高(實(shí)測(cè),抓取【軍艦】類,共抓取頁(yè)面近六千個(gè),費(fèi)時(shí)五十來(lái)分鐘,每分鐘能抓取超過(guò)一百個(gè)頁(yè)面),能準(zhǔn)確的保存分類信息。
最大的收獲在于深刻的理解了異步編程的整體流程控制。

相關(guān)文章

  • node.js基礎(chǔ)知識(shí)小結(jié)

    node.js基礎(chǔ)知識(shí)小結(jié)

    本文給大家匯總介紹了學(xué)習(xí)node.js的一些關(guān)于開發(fā)環(huán)境的基礎(chǔ)知識(shí),非常簡(jiǎn)單,給新手們參考下
    2018-02-02
  • Puppeteer解決SEO問題方法

    Puppeteer解決SEO問題方法

    這篇文章主要為大家介紹了Puppeteer解決SEO問題方法詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • 使用nvm安裝node的詳細(xì)圖文教程

    使用nvm安裝node的詳細(xì)圖文教程

    nvm是nodejs的版本管理工具,可以在一個(gè)環(huán)境中同時(shí)安裝多個(gè)nodejs 版本(和配套的 npm 版本),并隨時(shí)切換,下面這篇文章主要給大家介紹了關(guān)于使用nvm安裝node的詳細(xì)圖文教程,需要的朋友可以參考下
    2023-02-02
  • 輕松創(chuàng)建nodejs服務(wù)器(3):代碼模塊化

    輕松創(chuàng)建nodejs服務(wù)器(3):代碼模塊化

    這篇文章主要介紹了輕松創(chuàng)建nodejs服務(wù)器(3):代碼模塊化,本文是對(duì)第一節(jié)的例子作了封裝,需要的朋友可以參考下
    2014-12-12
  • Nodejs腳本實(shí)現(xiàn)批量修改文件

    Nodejs腳本實(shí)現(xiàn)批量修改文件

    當(dāng)我們想要更改一下所有的文件,如何可以在修改到這些文件的同時(shí)又能實(shí)現(xiàn)節(jié)省時(shí)間呢,通過(guò)這篇文章我們將來(lái)學(xué)習(xí)一下怎么通過(guò)這個(gè)腳本來(lái)實(shí)現(xiàn)這個(gè)功能,希望對(duì)大家有所幫助
    2023-11-11
  • node.js中使用socket.io制作命名空間

    node.js中使用socket.io制作命名空間

    這篇文章主要介紹了node中使用socket.io制作命名空間,需要的朋友可以參考下
    2014-12-12
  • nodejs提示:cross-device link not permitted, rename錯(cuò)誤的解決方法

    nodejs提示:cross-device link not permitted, rename錯(cuò)誤的解決方法

    這篇文章主要給大家介紹了關(guān)于nodejs提示:cross-device link not permitted, rename錯(cuò)誤的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用nodejs具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-06-06
  • NestJS核心概念之Middleware中間件創(chuàng)建使用示例

    NestJS核心概念之Middleware中間件創(chuàng)建使用示例

    這篇文章主要為大家介紹了NestJS核心概念之Middleware中間件創(chuàng)建使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • nodejs文件夾深層復(fù)制功能

    nodejs文件夾深層復(fù)制功能

    這篇文章主要介紹了nodejs文件夾深層復(fù)制功能,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-09-09
  • nodejs開發(fā)環(huán)境配置與使用

    nodejs開發(fā)環(huán)境配置與使用

    經(jīng)過(guò)幾個(gè)星期的nodejs學(xué)習(xí),從開始的小白到現(xiàn)在漸漸得熟悉,走過(guò)來(lái)也才算明白,現(xiàn)在已經(jīng)入門也掌握了相關(guān)的學(xué)習(xí)方法,今天開始記錄下自己學(xué)習(xí)的過(guò)程,以便日后查看。
    2014-11-11

最新評(píng)論