进去吧你!我要用代码把粉丝们塞到头图里去

2,956 阅读6分钟

我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!


前言

本文灵感来源于好朋友大帅的文章《用JS复原和同学头图创意》。大家如果用过B站,就会知道B站个人主页会有一张“头图”,一般情况下,大家的头图是一样的,但如果你有大会员会多一个头图自定义功能彰显个性。

我看到后第一个想法就是希望跟关注者们能有个互动,表达宠粉狂魔的感觉,没有什么比直接把他们可爱的头像装进去更合适了!大家可以点击村长的B站空间查看最终效果。

有不少小伙伴说没有看到自己,这是由于头图空间有限,以及B站1000条数据的限制,我只在这里显示最新关注的240个粉丝,且每天0点才能定时更新。所以如果你今天关注,明天就可能看到自己。最先关注我的十年老粉们如果降序排也是可以出现的,中间的小伙伴们就暂时不行啦😢

image-20220722091929519

整体步骤

下面大家可以跟我一起来看看如何实现这个创意。 我们整体需要以下几步:

  1. 获取B站接口所需令牌
  2. 获取B站粉丝数据
  3. 使用Canvas绘制头图
  4. 请求B站接口设置头图
  5. 使用GithubAction定时更新

你也可以看配套视频操作:

获取B站接口所需令牌

请求B站的接口需要提供当前用户身份信息,我们可以访问B站个人空间,通过Chrome浏览器开发者工具找到它们:

开发者工具 -> Application -> Cookies -> https://space.bilibili.com

所需信息分别是:DedeUserIDblili_jctSESSDATADedeUserID__ckMd5

把它们存下来,后面我们请求B站接口时候需要提供。

截屏2022-07-20 08.43.51

如何获取粉丝数据

探索

还有个问题是如何获取粉丝数据,我发现点击用户中心粉丝数可以查看自己粉丝情况

image-20220721144829353

注意看这里有个分页获取粉丝数据的接口followers

image-20220721145915751

看一下弹出的详情:https://api.bilibili.com/x/relation/followers,注意vmid、pn、ps等参数。

image-20220721145427381

但是竟然是个jsonp请求,能不能直接请求呢?去掉jsonp后面的部分,在浏览器里面发一个试试:

image-20220721150401335

ok啦!数据的问题解决了!注意face就是我们想要的用户头像信息。

这里有滥用用户信息的嫌疑,有可能被罚80亿🐶,如果有需要,小伙伴们通知我,我会删除这些图片

下面就是通过接口请求所需的数据,我们需要提供DEDEUSERID,以及分页和排序参数,url大致如下:

const url = "http://api.bilibili.com/x/relation/followers?" +
    "vmid=" + DEDEUSERID + "&order=desc&order_type=attention";

这里需要注意,使用ajax请求会受到限制,单页最多50条数据,最多访问20页数据,也就是我们最多可以获得1000个粉丝数据。我这里通过关注时间降序排序可以获得最新关注的用户信息,有点喜新厌旧的感觉,但是请大家相信我,如果可以,我希望把全部2w+关注者都塞进去。

关键代码

下面这部分关键代码实现:

探索题目

这里能不能模拟官网发送jsonp请求去获取数据,因为用户中心这里是可以获取20页之后的数据的。感兴趣的小伙伴可以探索一下,如果可行,大家一定要给我项目提个PR,那咱们可玩性就更强了,比如我们可以将本月生日的小伙伴全部画出来,又比如我们可以绘制女粉的头像,哈哈。

image-20220722095016614

使用Canvas绘制头图

思路

下面是将获取的粉丝头像绘制到画布上,我们通过canvas这个库实现(感谢大帅的创意),核心逻辑是:

  • 循环获取头像数据:使用canvas库提供的loadImage(url)获取图像数据

    // 加载图片
    const bgImage = await loadImage("bg.jpg");
    
  • 将获取图像绘制到画布:使用canvas提供的drawImage(img, x, y, width, height)绘制图片

    // 绘制图像:ctx是canvas实例提供的上下文
    ctx.drawImage(bgImage, 0, 0, canvasSize.w, canvasSize.h);
    
  • 绘制逻辑:画布尺寸2560 * 400,我们打算绘制240个头像(6行40列),那么每个头像尺寸约为64 * 64(2560*400/250,再开方得到64,除以240除不尽,强迫症改成了250,没别的意思哈,就是为了能除尽)

关键代码

code.juejin.cn/pen/7122736…

上传头图之前我们还可以导出图片确认一下绘制结果:

code.juejin.cn/pen/7122742…

请求B站接口设置头图

最后是将绘制的图像上传到B站头图,相关接口是https://space.bilibili.com/ajax/topphoto/uploadTopPhotov2,该接口需要用到前面我们获取的4个用户令牌信息。具体代码如下:

code.juejin.cn/pen/7122743…

本地在nodejs环境执行代码之后就可以看到更新的效果了!花花绿绿的,还挺好看!

image-20220721164757625

使用GithubAction定时更新头图

虽然前面已经可以做到想要的功能,但是粉丝每天都在变化,每隔一段时间更新一下头图应该会更好。所以我们就需要整一个定时任务来做这个自动更新。GithubAction就是一个很不错的选项,我们在github项目中定义一个工作流即可,大家可以在项目里创建.github/workflows/schedule.yml文件:

  • 我们定义了schedule事件,每天16点跑一次任务

  • jobs中我们定义执行任务,共分5步:

    • 迁出代码
    • 安装nodejs环境
    • 安装所需库
    • 安装项目依赖
    • 执行脚本
name: CI

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the main branch
  #push:
  #  branches: [ main ]
  schedule:
    - cron: '0 16 * * *'
  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
  # This workflow contains a single job called "build"
  build:
    # The type of runner that the job will run on
    runs-on: ubuntu-latest

    # Steps represent a sequence of tasks that will be executed as part of the job
    steps:
      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
      - uses: actions/checkout@v2

      # Runs a single command using the runners shell
      - name: Setup Node.js environment
        uses: actions/setup-node@v2.4.0

      - name: Setup Basically Packages
        run:
          sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
        
      - name: Install NPM dependencies
        run: 
          npm install
          
      - name: Run
        run:
          node index.js "${{secrets.BILI_JCT}}" "${{secrets.SESSDATA}}" "${{secrets.DEDEUSERID}}" "${{secrets.DEDEUSERID__CKMD5}}"

注意这里用到了github的秘钥功能,避免我们暴露这些关键信息给其他人,定义方式如下:

image-20220721170640794

相应的,代码中也要获取这些传入参数才行:

const [BILI_JCT, SESSDATA, DEDEUSERID, DEDEUSERID__CKMD5] = process.argv.slice(2);

使用项目

再次感谢大帅创意,原始项目地址,本文相关项目地址如下:

github.com/57code/auto…

使用该项目时,请按以下步骤走:

  1. fork项目
  2. 获取自己的秘钥信息
  3. 在自己项目settings中设置secrets
  4. 在actions中手动启动工作流

写在最后

如果大家觉得有帮助的话,给村长点个赞吧!

目前正在卷面试题,大家公众号搜村长学前端,加入羊村群,跟我们一起卷吧~