本文最后更新于:2022年9月9日 下午
在Hexo中显示你的发文折线图
在GitHub敲代码的时候,看见Profile里的Contributions统计图就会获得一股成就感,而Hexo中却没有这种功能,作为一个对前端一无所知的coder,最近现学现卖做了个实时同步的发文统计图,放在了“关于”页面。如下图所示,这个统计图能很适应地嵌入在正文中,并且鼠标放上去会有响应,不是简单的图片。

制作这个的基本流程如下图所示,基本思路是通过GitHub的API来获取寄放在GitHub Pages上的本网站的repo,之后由于hexo将文章排序按照时间规律分目录存储,可以获取到各个时间段的发文数量。这个数据之后通过很便宜甚至能白嫖的腾讯云Severless云函数来实时获取,最后在我们的网站中只需要简单访问云函数的API就可以获得数据。
graph LR
A[获取GitHub API权限] --> B[用Python写好获取发文数据的函数]
B --> C[将函数部署为云函数]
C --> D[配置Hexo导入要用的第三方JS库]
D --> E[在文章插入JS代码]
获取GitHub API权限
由于GitHub的API就能方便地提供我们需要的信息,所以我们不需要费心用各种方法去爬取。GitHub的REST API是RESTful架构的教科书级参考,非常好用易懂,文档也很全面:GitHub REST API - GitHub Docs。我们主要用到其查询commits和查询tree的API。使用API需要先获得Personal access token,可以在这里生成(这个页面在Settings -> Developer settings -> Personal access tokens
下),假如只是实现我们这个功能不需要勾选任何权限,也不推荐勾选过多的权限。
⚠️要注意这个token只显示一次,及时保存。
使用Python获取发文数据
使用requests
就能轻松的访问API,我这里文章的目录结构是<年份>/<月份>/<日>/<标题>/页面
,年份直接在根目录下。为了之后部署在云函数上,需要以Flask的形式写。两个库的细节就不说啦,代码含义见注释。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| @app.route("/github/<owner>/<repo>") def main(owner, repo): secret_token = "你的token" headers = { 'Accept': "application/vnd.github+json", 'Authorization': f"Bearer {secret_token}" } api_url = f"https://api.github.com/repos/{owner}/{repo}/commits" rsp = requests.get(api_url, headers=headers) tree_url = json.loads(rsp.content)[0]['commit']['tree']['url'] rsp = requests.get(tree_url, headers=headers) year_root_url = [] for item in json.loads(rsp.content)['tree']: p: str = item['path'] if p.isdigit() and p.startswith('20') and len(p) == 4: year_root_url.append([p, item['url']]) blog_info = [] for yr, yr_url in year_root_url: rsp = requests.get(yr_url, headers=headers, params={'recursive': True}) for item in json.loads(rsp.content)['tree']: if item['type'] == 'blob': month, day, name, _ = item['path'].split('/') blog_info.append([yr, month, day, name]) blog_counter = {} for yr, mo, _, _ in blog_info: date = f"{yr}/{mo}" if date in blog_counter: blog_counter[date] += 1 else: blog_counter[date] = 1 result_dict = { "labels": list(blog_counter.keys()), "values": list(blog_counter.values()), } return jsonify(data=result_dict)
|
部署到云函数上
在腾讯云打开Serverless的控制台(第一次用可能要授权什么的,但是很简单),然后在函数服务中用模板创建一个flask的云函数。

函数创建成功后,点开云函数,可以在线编辑代码,找到里面的app.py
,加上之前写好的代码,然后在requirements.txt
中添加requests库,最后点击编辑器右上角的部署就可以啦。

要访问云函数,则点开Severless应用,然后找到URL,之间点开应该就能看到模版自带的欢迎界面,出现这个界面就表示应用成功了。之后可以用postman等工具来测试自己写的代码能不能用。


配置Hexo
要在hexo中访问我们的云函数,以及之后的可视化,需要使用第三方的js库,但是并不能直接在文章中用<script>
标签引入。(不太懂为啥不能,反正试过了)
要解决这个问题,我们使用Hexo 5 注入器,在生成页面的头部加上对应要导入的<script>
标签。
根据上面这个链接的教材,我们在<blog目录>/themes/<主题>/scripts
下新建一个injector.js
,内容为:
1 2 3 4
| hexo.extend.injector.register('head_begin', ` <script src="/js/Chart.js"></script> <script src="https://cdn.jsdelivr.net/npm/jquery@3.6.1/dist/jquery.min.js"></script> `)
|
此处假如用CDN就直接贴链接,假如用本地相对目录,则是以<blog目录>/source
为根目录的相对路径。我们要使用的可视化工具为Chart.js。并且由于我只学过一点点jquery,所以就导入jq来访问云函数了。
在文章中插入
为了控制大小,用一个div包裹住canvas,canvas在js中绑定为一个new Chart。由于对前端不是很熟,就进行了一些小小的配置,懂js的老哥应该能写得比我好很多hhhh。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| <div class="chart-container" style="position: relative; height:80%; width:100%"> <canvas id="myChart"></canvas> </div>
<script> $.getJSON("https://<你的云函数链接>/release/github/Kamino666/kamino666.github.io", function(api_data){ const ctx = document.getElementById('myChart').getContext('2d'); const myChart = new Chart(ctx, { type: 'line', data: { labels: api_data.data.labels, datasets: [{ label: '发表博客数量', data: api_data.data.values, backgroundColor: ["rgba(238, 238, 238, 0.2)"], borderColor: ["rgba(0, 173, 181, 1)"], borderWidth: 2, pointBorderWidth: 2, pointHoverBorderWidth: 4, pointHoverBackgroundColor: "rgba(0, 0, 0, 0)", pointHoverBorderColor: "rgba(0, 173, 181, 1)", pointHitRadius: 15, pointBackgroundColor: "rgba(238, 238, 238, 1)", }] }, options: { responsive: true, scales: { yAxes: [{ ticks: { beginAtZero:true } }] }, legend: { display: false }, title: { display: true, fontSize: 18, text: "Kamino发表博客的数量" } } }); }) </script>
|
Q&A
Q:为什么要用云函数,不直接用js访问GitHub API?
A:因为我不会js。因为用js的话token会暴露出去,可能不是很安全。
Q:为什么这么麻烦,每次更新的时候直接生成新的数据就不用云函数了。
A:因为浪漫每次更新生成新数据也挺麻烦,而且这套流程也很适合练手。
Q:为什么要通过GitHub?我的Hexo不寄存在GitHub怎么办?
A:目前的解决方法不是最佳的,最佳应该是每次hexo g
的时候自动生成对应的数据和代码,但是对这部分就更更更不熟悉了……