我們這節的目標是學習完本節課程後,能進行網頁簡單的分析與抓取,對抓取到的資訊進行輸出和文字儲存。
爬蟲的思路很簡單:
確定要抓取的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年開始負責集團公司的專利工作,在此之前幾乎沒有專門的組織負責,算是從零起步。最開始想的很簡單,就是我已宣布,大家都覺得是個好事兒,又提公升公司品牌度,又提公升發明人個人品牌度,新業務研發領域的專利申請應該是...