NodeJS單線程、事件驅動的特性能夠在單臺機器上實現極大的吞吐量,很是適合寫網絡爬蟲這種資源密集型的程序。html
這段時間寫了一個能夠爬取知乎關係鏈的小爬蟲,輸入某個用戶的用戶主頁URL,就能夠爬取他的關係鏈:
https://github.com/starkwang/Zhihu-Spider前端
數據請求方面使用了request這個模塊,用express響應請求,前端構圖使用了Echarts,中間數據交互是用websocket作的。node
主要用到了知乎的兩個API:git
//獲取目標用戶的關注者 POST https://www.zhihu.com/node/ProfileFollowersListV2 參數: method:"next", //填入next便可 params:{ offset:40, //20的倍數,從0開始每次拉取20個關注者 order_by:"created", //填入"created"便可 hash_id:"d965f32a168564f9e58ad3a48a1585a4" //目標用戶在知乎惟一的hash_id }, _xsrf:"289c6ef5534d3dbb6a54057826864799" //xsrf參數,cookie中給定的
//獲取目標用戶關注的人 POST https://www.zhihu.com/node/ProfileFolloweesListV2 參數: method:"next", //填入next便可 params:{ offset:40, //20的倍數,從0開始每次拉取20個關注的人 order_by:"created", //填入"created"便可 hash_id:"d965f32a168564f9e58ad3a48a1585a4" //目標用戶在知乎惟一的hash_id }, _xsrf:"289c6ef5534d3dbb6a54057826864799" //xsrf參數,cookie中給定的
爬蟲的工做流程以下:es6
獲取目標用戶的關注者、關注的人列表,找出和他相互關注的人(即朋友)github
對朋友列表裏的朋友重複1中的步驟,找出朋友的朋友列表web
遍歷2中的結果,找出朋友之間的相互關注關係express
首先咱們寫一個getUser
方法,它的做用是請求一個用戶主頁URL,獲取請求結果,解析出用戶的暱稱、hash_id、關注者數量、關注的人數量。promise
var request = require('request'); var Promise = require('bluebird'); var config = require('../config'); function getUser(userPageUrl) { return new Promise(function(resolve, reject) { request({ method: 'GET', url: userPageUrl, headers: { 'cookie': config.cookie } }, function(err, res, body) { if (err) { reject(err); } else { resolve(parse(body)); } }) }); } function parse(html) { var user = {}; var reg1 = /data-name=\"current_people\">\[.*\"(\S*)\"\]<\/script>/g; reg1.exec(html); user.hash_id = RegExp.$1; var reg2 = /關注了<\/span><br \/>\n<strong>(\d*)/g; reg2.exec(html); user.followeeAmount = parseInt(RegExp.$1); var reg3 = /關注者<\/span><br \/>\n<strong>(\d*)/g; reg3.exec(html); user.followerAmount = parseInt(RegExp.$1); var reg4 = /<title> (.*) - 知乎<\/title>/g reg4.exec(html); user.name = RegExp.$1; return user; } module.exports = getUser;
接下來須要一個fetchFollwerOrFollwee
方法,它的做用是輸入上面的user對象,根據在第二部分介紹的API,抓取出用戶的全部關注的人或者關注者,使用方法相似(使用es6):websocket
getUser('someURL') .then(user => fetchFollwerOrFollwee({user: user, isFollowees: false}) .then(list => console.log(list))
具體代碼參照這裏,就不貼上來了
接下來要作的就是組合getUser
和fetchFollwerOrFollwee
,變成一個getFriends
方法,輸入是用戶頁URL,輸出是用戶的好友列表,大概像這樣:
function getFriends(someURL){ getUser(someURL) .then(user => fetchFollwerOrFollwee(...)) .then((followersList, follweesList) => findFriends(followersList, follweesList)) }
而後咱們能夠封裝一個最後的searchSameFriend
方法,輸入是某個user和一個好友列表myFriends,輸出是這個user的全部好友中,也在列表myFriends中的好友
function searchSameFriend(user, myFriends){ return getFriends(user.url) .then(user => findSameFriends(userFriends, myFriends)) .then(sameFriends => console.log(sameFriends)) }
最後整個爬蟲的promise流程大概是這樣的:
function Spider(){ return getUser(URL) .then(user => getFriends(user)) .then(userFriends => Promise.map(userFriends, friend => searchSameFriend(friend,userFriends)) ) }
固然其中缺乏了部分用websocket和前端數據交互的代碼