用NodeJS爬取知乎的關係鏈

1、介紹

NodeJS單線程、事件驅動的特性能夠在單臺機器上實現極大的吞吐量,很是適合寫網絡爬蟲這種資源密集型的程序。html

這段時間寫了一個能夠爬取知乎關係鏈的小爬蟲,輸入某個用戶的用戶主頁URL,就能夠爬取他的關係鏈:
https://github.com/starkwang/Zhihu-Spider前端

圖片描述


2、爬蟲的實現

數據請求方面使用了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

  1. 獲取目標用戶的關注者、關注的人列表,找出和他相互關注的人(即朋友)github

  2. 對朋友列表裏的朋友重複1中的步驟,找出朋友的朋友列表web

  3. 遍歷2中的結果,找出朋友之間的相互關注關係express


3、部分代碼

首先咱們寫一個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))

具體代碼參照這裏,就不貼上來了

接下來要作的就是組合getUserfetchFollwerOrFollwee,變成一個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和前端數據交互的代碼

相關文章
相關標籤/搜索