原文地址:NodeJS網絡爬蟲
網上有很多其他語言平台版本的網絡爬蟲,比如Python,Java。那怎么能少得了我們無所不能的javascript呢😂?這個和之前給產品狗開發的批量圖片下載配置工具,原理很相似,核心就是調用Node的http模塊。
網絡爬蟲基本就由如下部分組成:
- 程序入口
- 請求模塊
- 數據解釋
程序入口可以用web頁面實現,還可以在網頁上顯示抓取的數據和分析結果;但是這個我只想把精力花在核心模塊,頁面和樣式不想花太多精力去弄。所以呢,我就開發個node的命令行工具,這個比較成熟的就是commander了。
請求模塊方面,我只想抓取百度的頁面,還有知乎的頁面,它們的請求都是https協議的,好在Node的https和http模塊功能幾乎是一樣的,這里需要做的就是熟悉它的api就好了,也是easy。
數據解釋模塊,因為抓取出來的頁面內容是字符串,所以可以用正則表達式去匹配,但是這樣太麻煩了。有沒有更好的方式?抓取回來可都是html內容,用jQuery以操作dom的方式去解析數據不是很方便嘛,恰好有個服務端的jquery庫cheerio。
頁面抓取完,數據也分析出來了,那就非常簡單了,你可以選擇存入數據庫或者寫入文件保存。接下來就開始實現上面的功能模塊。
程序入口
開始配置和初始化commander,具體的使用方式參考官方的文檔:https://www.npmjs.com/package/commander,這里不再詳細解釋用法了,下面開始配置commander。
首先要在package.json添加如下節點,表示注冊了一個命令行 "grab"。
"bin": {
"grab": "bin/grab.js"
},
接着在grab.js開始定義commander,最后我們就可以這樣執行命令行:"grab baidu <內容>",當然可以用bd簡寫代替baidu,知乎的定義和百度是一樣,這里不再重復介紹了。
program
// .allowUnknownOption()//不報錯誤
.version('0.0.1')
.usage('這是我的網絡爬蟲程序😎'
+'\n grap [option]'
+'\n bd baidu: baidu search'
+'\n zh zhihu: zhihu search');
program
.command('baidu <cmd>')
.alias('bd')
.description('baidu search baidu')
.option("-t, --tieba", "baidu tieba")
.action(function(cmd, options){
console.log('baidu search "%s":', cmd);
request.baiduSearch(cmd);
}).on('--help', function() {
console.log(' Examples:');
console.log();
console.log(' grab bd <cmd>');
console.log(' grab baidu <cmd>');
console.log();
});
program.parse(process.argv);
請求模塊
https模塊發起請求主要有兩種方式,這里稍微封裝了下:
- get方式,主要針對的是簡單的請求,只需要傳遞url發起get請求。知乎的調用這個就可以了。
function get(url,callback) {
return https.get(url,function(response) {
var body = '';
response.on('data', function(data) {
body += data;
});
response.on('end', function() {
callback(body);
});
});
}
- requerst方式,不但可以發起get請求,也可以發起post請求,還可以修改端口,請求header。這個主要是針對限制比較多的百度爬蟲。百度必須設置header,同時百度請求參數也比較復雜,需要專門配置,具體可參考網上的資料。
function request(options,callback){
// var postData = qs.stringify({});
var body,
req = https.request(options, (res) => {
console.log('STATUS: ' + res.statusCode);
// console.log('HEADERS: ' + JSON.stringify(res.headers));
res.setEncoding('utf8');
res.on('data', function (chunk) {
body+=chunk;
});
res.on('end',function(){
callback(body)
});
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
});
// write data to request body
// req.write(postData);
req.end();
}
function baiduRequset(pageNo,pageSize,keyword){
var path='/s?'+qs.stringify({
ie:'utf-8',
f:8,
rsv_bp:1,
tn:'baidu',
rn:pageSize,
pn:pageNo*pageSize,
wd:keyword
}),
options = {
hostname: 'www.baidu.com',
port: 443,
path: path,
method: 'GET',
headers: {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
}
};
request(options,function(body){
saveFile(pageNo,keyword,body);
showBaiduResult(pageNo,body);
});
}
數據解釋
抓取數據之后,我們需要做的就是調用cheerio,以jquery獲取dom內容的方式獲取結果,並顯示出來,當然也可以保存文件或數據庫。
/**
* 顯示結果
* @param {[type]} pageNo [description]
* @param {[type]} body [description]
* @return {[type]} [description]
*/
function showBaiduResult(pageNo,body){
var title,summary,link,
reg=/<[^<>]+>/g,
$ = cheerio.load(body,{decodeEntities: false});
$('#content_left .result').each(function(i,item){
var $a = $(item).find('h3 a');
title = $a.html();
link = $a.attr('href');
summary=$(item).find('.c-abstract').html();
if(title){
console.log(`第${pageNo+1}頁 第${i+1}條`);
console.log(`link: ${link}`.green);
// console.log(`title: ${title}`);
console.log('title: ');
ouputColor(title);
if(summary){
// console.log(`summary: ${summary}`);
console.log('summary: ');
ouputColor(summary);
}
}
console.log('------------------------------');
console.log('');
});
}
// 知乎
exports.zhihuSearch=function(keyword,cb){
get('https://www.zhihu.com/search?type=content&q='+keyword,function(content){
var title,summary;
var $ = cheerio.load(content,{decodeEntities: false});
saveFile(0,keyword,content);
$('.list .item').each(function(i,item){
title=$(item).find('.js-title-link').html();
summary=$(item).find('.summary').html();
if(title){
// title=(''+title).replace(/<[^<>]+>/g,'');
// summary=(''+summary).replace(/<.+>/g,'');
console.log('title: ');
ouputColor(title);
if(summary){
console.log('summary: ');
ouputColor(summary);
}
}
console.log('------------------------------');
console.log('');
});
});
};
執行爬蟲
功能完成后,先試驗一下抓取知乎的內容
grab zh webgl
抓取到的html文件保存在download文件夾,同時在命令行顯示抓取結果。
如果要執行百度的爬蟲,運行如下命令行即可
grab bd webgl
總結
這里完成的是最基本的爬蟲功能,代碼請看net_grab