粉丝统计代码解析(雾

· · 个人记录

似乎接口还没有挂,但是最好还是不要瞎用

测试uid=3时可以正常访问第320页

当我们用chrome抓包时会发现这个
API地址:https://www.luogu.com.cn/fe/api/user/followers?user=55812&page=1
用法应该都能看出来
然后我们调用这个API 返回了一个json文件

    {
    "users": {
        "result": [{
            "blogAddress": null,
            "followingCount": 1,
            "followerCount": 0,
            "ranking": null,
            "userRelationship": 0,
            "reverseUserRelationship": 1,
            "passedProblemCount": 0,
            "submittedProblemCount": 4,
            "uid": 113742,
            "name": "hnnnb",
            "slogan": "",
            "badge": null,
            "isAdmin": false,
            "isBanned": false,
            "color": "Gray",
            "ccfLevel": 0
        }, {
            "blogAddress": "https:\/\/www.luogu.com.cn\/blog\/123456789chq\/",
            "followingCount": 260,
            "followerCount": 11,
            "ranking": 47262,
            "userRelationship": 0,
            "reverseUserRelationship": 1,
            "passedProblemCount": 151,
            "submittedProblemCount": 471,
            "uid": 88341,
            "name": "chenhaiquan",
            "slogan": "",
            "badge": null,
            "isAdmin": false,
            "isBanned": false,
            "color": "Blue",
            "ccfLevel": 0
        }, {
            "blogAddress": "https:\/\/Rekisholm.blog.luogu.org\/",
            "followingCount": 45,
            "followerCount": 20,
            "ranking": 2981,
            "userRelationship": 0,
            "reverseUserRelationship": 1,
            "passedProblemCount": 567,
            "submittedProblemCount": 1710,
            "uid": 105286,
            "name": "\u4eac\u6da6",
            "slogan": "\u8fd9\u4e2a\u5946\u4f6c\u5f88\u725b\u903c\uff0c\u4e13\u6ce8\u4e8e\u5b66\u4e60\uff0c\u56e0\u6b64\u4ec0\u4e48\u4e5f\u6ca1\u6709\u7559\u4e0b",
            "badge": "",
            "isAdmin": false,
            "isBanned": false,
            "color": "Green",
            "ccfLevel": 4
        }
        ...
        ],
        "perPage": 20,
        "count": 65
    }
}

返回的count应该是总粉丝数,perPage似乎一直是20,应该是每页应该有多少个

| 内码 | 代表什么 | | :-----------: | :-----------: | | $blogAddress$ | 博客地址 | | $followingCount$ | 关注数 | | $followerCount$ | 粉丝数 | | $ranking$ | 排名 | | $userRelationship$ | 是否关注了你 | | $reverseUserRelationship$ | 有没有关注他 | | $passedProblemCount$ | 过了几题 | | $submittedProblemCount$ | 交了几次 | | $uid$ | $uid$ | | $name$ | 名称 | | $slogan$ | 签名 | | $badge$ | 名字后面的标签 | | $isAdmin$ | 是不是管理 | | $isBanned$ | 是不是被封禁 | | $color$ | 名字颜色 | | $ccfLevel$ | $ccf$评级 | 再调用一个不存在的页面 ![aZ9MQO.png](https://s1.ax1x.com/2020/07/29/aZ9MQO.png) 这时候就只会找到一个空的$result

我们可以想到一个暴力方法
请求每一个pageresult为空时停止
但是这样只能写成同步,要是异步就会变成
我们访问完了最后一个page,但是要是这个page还没有响应,你应该怎么做?

  1. 继续下一个page
    这样可能会访问极多的空result,会被封
  2. 等待这个page响应
    恭喜你写出了同步方法

这时候返回的perPagecount就有用了
先算出总共有多少页,然后再去请求
然后我们就得到了铃酱的代码

function f_request_sync(url) {
    var xhr = new XMLHttpRequest();
    xhr.open("GET", url, false);
    xhr.send(null);
    if (xhr.status != 200) return;
    return JSON.parse(xhr.response);
}
function f_request(url, id) {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200)
                f_handle(JSON.parse(xhr.response));
            else f_error(id);
        }
    }
    xhr.open("GET", url, true);
    xhr.send(null);
}
const f_uid = 90893;
var f_users = [];
var f_queue = [];
var f_id;
var f_succ = 0, f_pages;
function f_handle(data) {
    f_users.push.apply(f_users, data.users.result);
    f_succ++;
}
function f_error(id) {
    f_queue.push(id);
}
function f_work() {
    console.log(f_succ+'/'+f_pages);
    if (f_pages == f_succ) {
        clearInterval(f_id);
        f_info();
        return;
    }
    var t = 10;
    while (t > 0 && f_queue.length > 0) {
        t--;
        var id = f_queue.pop();
        f_request('https://www.luogu.com.cn/fe/api/user/followers?user='+f_uid+'&page='+id, id);
    }
}
function f_main() {
    var data = f_request_sync('https://www.luogu.com.cn/fe/api/user/followers?user='+f_uid+'&page=1');
    var count = data.users.count, per_page = data.users.perPage;
    f_pages = Math.ceil(data.users.count / data.users.perPage);
    for (var i = 1; i <= f_pages; i++)
        f_queue.push(i);
    f_id = setInterval(f_work, 1000);
}
function f_info() {
    var f_followers = f_users.length;
    var f_color = {Cheater:0,Gray:0,Blue:0,Green:0,Orange:0,Red:0,Purple:0};
    var f_ccflevel = {'0':0,'3':0,'4':0,'5':0,'6':0,'7':0,'8':0,'9':0,'10':0};
    var f_badge = 0;
    var f_banned = 0;
    var f_sum_follower = 0;
    var f_sum_following = 0;
    var f_sum_uid = 0;
    var f_friends = 0;
    for (var i = 0; i < f_followers; i++) {
        var c = f_users[i];
        f_color[c.color]++;
        f_ccflevel[c.ccfLevel]++;
        if (c.badge) f_badge++;
        if (c.isBanned) f_banned++;
        f_sum_follower += c.followerCount;
        f_sum_following += c.followingCount;
        f_sum_uid += c.uid;
        if (c.userRelationship) f_friends++;
    }
    console.log('followers: '+f_followers);
    console.log('color: ');
    for (var x in f_color)
        console.log('\t'+x+': '+f_color[x]);
    console.log('ccflevel: ');
    for (var x in f_ccflevel)
        console.log('\t'+x+': '+f_ccflevel[x]);
    console.log('has badge: '+f_badge);
    console.log('banned: '+f_banned);
    console.log('average follower count: '+f_sum_follower/f_followers);
    console.log('average following count: '+f_sum_following/f_followers);
    console.log('average uid: '+f_sum_uid/f_followers);
    console.log('friends: '+f_friends);
}
f_main();

javascript没高亮差评
不过似乎没加锁