用 NodeJS 爬取知乎的關系鏈

sunny_hlh 8年前發布 | 10K 次閱讀 Node.js Node.js 開發

一、介紹

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

這段時間寫了一個可以爬取知乎關系鏈的小爬蟲,輸入某個用戶的用戶主頁URL,就可以爬取他的關系鏈:

二、爬蟲的實現

數據請求方面使用了 request 這個模塊,用express響應請求,前端構圖使用了 Echarts ,中間數據交互是用websocket做的。

主要用到了知乎的兩個API:

//獲取目標用戶的關注者

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中給定的

爬蟲的工作流程如下:

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

2. 對朋友列表里的朋友重復1中的步驟,找出朋友的朋友列表

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

三、部分代碼

首先我們寫一個 getUser 方法,它的作用是請求一個用戶主頁URL,獲取請求結果,解析出用戶的昵稱、hash_id、關注者數量、關注的人數量。

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):

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和前端數據交互的代碼

 

來自:http://zhuanlan.zhihu.com/p/20683518

 

 本文由用戶 sunny_hlh 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!