青训营 X 码上掘金:遇见

114 阅读3分钟

当青训营遇上码上掘金

我选择主题2:遇见。

将青训营的所有小伙伴们的绘制到了一张可视化知识图谱上,以小伙伴们之间的关注作为节点间的联系。

展示效果如下:

1.png

2.png

3.png

1. 数据来源

本文以关注过 青训营官方账号 的前 100 个用户集合作为研究对象,主要需要他们的用户名、头像等信息(这些都是公开的数据信息)。

1.1. 用户信息

获取某个掘金账户粉丝的 API 请求格式如下:

GET https://api.juejin.cn/user_api/v1/follow/followers?user_id=3386151545092589&cursor=20
  • user_id 表示要获取哪个用户的粉丝。
  • cursor 是偏移,相当于页号的功能,接口一次返回最多 20 条数据,需要滚动翻页。
  • 3386151545092589青训营官方账号user_id

获取到的数据格式如下:

{
    "err_no": 0,
    "err_msg": "success",
    "data": {
        "count": 8160,
        "cursor": "40",
        "data": [
            {
                "user_id": "xxxxxxxxxxxxxx",
                "user_name": "xxx",
                "avatar_large": "xxxxxxxx",
                "level": 2,
                "description": "",
                "isfollowed": false,
                // ...
            },
            // ...
        ],
        "hasMore": true
    }
}

爬取代码如下:

const sleep = (timeout) => {
  return new Promise((resolve)=>{
    setTimeout(()=>{
      resolve();
    }, timeout)
  })
}

// fetch API 封装
const get = async function(url) {
  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`Net Error: ${response.status}`);
  }
  const jsonBody = await response.json();
  return jsonBody;
}

for (let i = 0; i < 100; i+=20) {
  const response = await get('https://api.juejin.cn/user_api/v1/follow/followers?user_id=3386151545092589&cursor=' + i)
  
  const followers = response.data.data.map(follower => {
    return {
      user_id: follower.user_id,
      user_name: follower.user_name,
      avatar_large: follower.avatar_large,
    }
  })
  save(followers)

  // 休眠一会, 避免压垮服务器
  await sleep(200);
}

1.2. 用户联系

我选取了用户与用户之间关注作为联系,关注关系是单向的。为了保护隐私演示代码不会取真实的关注数据,通过分区采样的方式来随机生成用户关注数据。

// 生成 [n,m] 的随机整数
function randomNum(minNum, maxNum){ 
    return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10); 
}

var links = []

// 对区间 [min, max] 中的节点, 随机生成 times 次关系
function randomLinks1(min, max, times){ 
    for (let i = 0; i < times; i++) {
        links.push({
            source: randomNum(min, max),
            target: randomNum(min, max),
        })
    }
}

// 从区间 [min1, max2] 和 [min2, max2] 分别随机取一个节点连接关系, 生成 times 次
function randomLinks2(min1, max1, min2, max2, times){ 
    for (let i = 0; i < times; i++) {
        links.push({
            source: randomNum(min1, max1),
            target: randomNum(min2, max2),
        })
    }
}


randomLinks1(0, 9, 8)
randomLinks1(10, 29, 30)
randomLinks1(30, 79, 40)
randomLinks1(80, 99, 40)

randomLinks2(0, 9, 30, 79, 5)
randomLinks2(80, 99, 30, 79, 3)
randomLinks2(0, 9, 30, 79, 1)
randomLinks2(10, 29, 80, 99, 4)

2. 绘制可视化图谱

  1. 引入 Echars 库
<script src="https://cdnjs.cloudflare.com/ajax/libs/echarts/5.4.1/echarts.min.js"></script>
  1. 设置力引导布局,节点之间使用斥力分开彼此
force: {
    repulsion: 300,
    edgeLength: 1200,
    gravity: 0.5,
    // layoutAnimation: false
},
  1. 设置选中节点或边时,高亮展示相关联的节点和边
emphasis: {
    focus: 'adjacency',
    lineStyle: {
        width: 2,
        color: 'red'
    }
},
  1. 使用掘金小伙伴的头像作为节点的形状展示
var data = []
for (let i = 0; i < users.length; i++) {
    data.push({
        id: users[i].id,
        name: users[i].name,
        symbol: 'image://' + users[i].avatar,
    })
}

3. 结语

制作这个好友关系可视化图谱,希望可以通过其为青训营的小伙伴们发现更多志同道合的朋友。大家一起学习、一起进步,祝大家都能在此处青训营中学习到知识、交到朋友。

4. 附录:代码