惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

大猫的无限游戏
大猫的无限游戏
J
Java Code Geeks
小众软件
小众软件
D
Docker
腾讯CDC
H
Hackread – Cybersecurity News, Data Breaches, AI and More
V
V2EX
博客园 - 叶小钗
GbyAI
GbyAI
Microsoft Azure Blog
Microsoft Azure Blog
Stack Overflow Blog
Stack Overflow Blog
B
Blog RSS Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
博客园 - 【当耐特】
IT之家
IT之家
博客园 - 司徒正美
M
MIT News - Artificial intelligence
T
The Blog of Author Tim Ferriss
The GitHub Blog
The GitHub Blog
罗磊的独立博客
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
C
Check Point Blog

元视角

.NET 生态下的 Agent 框架选型:从 ReAct 到原生推理 - 元视角 从「能用」到「好用」:LLM 流式响应实现方式的探索之路 - 元视角 当我用 2000 条聊天记录,让 AI 为我画一幅自画像 - 元视角 基于 Supabase 的 AI 应用开发探索 - 元视角 微博 × MCP:社交媒体新玩法解锁 - 元视角 四点钟海棠花未眠 - 元视角 Semantic Kernel × MCP:智能体的上下文增强探索 - 元视角 基于 K-Means 聚类分析实现人脸照片的快速分类 - 元视角 容器技术驱动下的代码沙箱实践与思考 - 元视角 温故而知新:后端通用查询方案的再思考 - 元视角 浅议 CancellationToken 在前后端协同取消场景中的应用 - 元视角 Semantic Kernel 视角下的 Text2SQL 实践与思考 - 元视角 关于 ChatGPT 的流式传输,你需要知道的一切 - 元视角 RAG 的是与非、Rewrite 和 Rerank - 元视角 使用 EFCore 和 PostgreSQL 实现向量存储及检索 - 元视角 基于 LLaMA 和 LangChain 实践本地 AI 知识库 - 元视角 使用 llama.cpp 在本地部署 AI 大模型的一次尝试 - 元视角 如何为 Git 配置多个 SSH Key - 元视角 C# 使用 LibUsbDotNet 实现 USB 设备检测 - 元视角 基于 C# 实现样式与数据分离的打印方案 - 元视角 基于 SVG 的图形交互方案实践 - 元视角 前端视频播放技术概览 - 元视角 温故而知新,再话 Python 动态导入 - 元视角 后 GPT 时代,NLP 不存在了? - 元视角 视频是不能 P 的系列:使用 Milvus 实现海量人脸快速检索 - 元视角 GDI+下字体大小自适应方案初探 - 元视角 小爱音箱集成 ChatGPT 的不完全教程 - 元视角 程序员视角下的三体世界随想 - 元视角 关于 Docker 容器配置信息的渐进式思考 - 元视角 在 Docker 容器内集成 Crontab 定时任务 - 元视角
使用 Python 生成博客目录并自动更新 README - 元视角
飞鸿踏雪 · 2018-02-23 · via 元视角

各位朋友,大家好,我是 Payne,欢迎大家关注我的博客,我的博客地址是:https://qinyuanpei.github.io。首先在这里祝大家春节快乐,作为过完年以后的第一篇文章,博主想写点内容风格相对轻松的内容。自从博主的博客采用 TravisCI 提供的持续集成(CI)服务以以来,博客的更新部署变得越来越简单,所有的流程都被简化为 Git 工作流下的 提交(commit) 和 推送(push) 操作。考虑到博客是托管在 Github 上的,一直希望可以自动更新仓库主页的 README 文件,这样可以显示每次提交代码后的变更历史。基于这样一个构想,我想到了为博客生成目录并自动更新 README,其好处是可以为读者建立良好的文档导航,而且 Markdown 是一种简单友好的文档格式,Github 等代码托管平台天生就支持 Markdown 文档的渲染。关于博客采用 TravisCI 提供持续集成(CI)服务相关内容,可以参考 持续集成在 Hexo 自动化部署上的实践 这篇文章。

好了,现在考虑如何为博客生成目录,我们这里需要三个要素,即标题、链接和时间。标题和时间可以直接从 _posts 目录下的 Markdown 文档中读取出来,链接从何而来呢?我最初想到的办法是读取每个 Markdown 文档的文件名,因为我的使用习惯是采用英文命名,这样当博客的永久链接(permalink)采用默认的 :year/:month/:day/:title/ 形式时,每个 Markdown 文档的文件名等价于文章链接。事实证明这是一个愚蠢的想法,因为当你改变永久链接(permalink)的形式时,这种明显投机的策略就会彻底的失败。相信你在浏览器种打开这篇文章时,已然注意到链接形式发生了变化,当然这是我们在稍后的文章中讨论的话题啦。至此,我们不得不寻找新的思路,那么这个问题该如何解决呢?

我意识到我的博客配置了 hexo-generator-json-content 插件,这个插件最初的目的是为博客提供离线的搜索能力,该插件会在博客的根目录里生成一个 content.json 文件,而这个文件中含有我们想要的一切信息,因此我们的思路转变为解析这个文件,人生苦短啊,我果断选择了我最喜欢的 Python,这里我们会提取出所有的文章信息,按照日期由近到远排序后生成列表。Python 强大到让我觉得这篇文章无法下笔,所以这里直接给出代码啦:

# -*- coding: utf-8 -*-

import os
import re
import sys
import json
import datetime

# 文档实体结构定义
class Post:

    def __init__(self,date,link,title):
        self.date  = date
        self.link  = link
        self.title = title

    def getTitle(self):
        return self.title

    def getLink(self):
        return 'https://qinyuanpei.github.io/' + self.link

    def getDate(self):
        d = re.findall(r'\d{4}-\d{1,2}-\d{1,2}',self.date)[0]
        t = re.findall(r'\d{2}:\d{2}:\d{2}',self.date)[0]
        dt = '%s %s' % (d,t)
        return datetime.datetime.strptime(dt,'%Y-%m-%d %H:%M:%S')

# 从JSON中加载文档数据
def loadData():
    json_file = open('./public/content.json','rb')
    json_data = json.load(json_file)
    for item in json_data:
        yield Post(item['date'],item['path'],item['title'])

# 从列表生成Markdown文件
def mkMarkdown(items):
    mdfile = open('README.md',mode='wt',encoding='utf-8')
    itemTpl = '* {0} - [{1}]({2})\n'
    for item in items:
        mdfile.write(itemTpl.format(
            datetime.datetime.strftime(item.getDate(),'%Y-%m-%d'),
            item.getTitle(),
            item.getLink()
        ))



if(__name__ == "__main__"):
    items = sorted(loadData(),key=lambda x:x.getDate(),reverse=True)
    mkMarkdown(items)

这里需要注意的有两个地方,第一,从 JSON 中解析出来的日期形式为:2018-02-23T01:32:45.000Z。对于这个形式的日期,博主先后尝试了内建的 time 模块和第三方的 datetime 模块,发现均无法直接转换为日期类型,所以首先采用正则匹配出日期和时间,然后再组合为标准的 %Y-%m-%d %H:%M:%S 的格式,这样就可以使用 datetime 模块进行处理啦,我还是想吐槽人类对各种各样 format 的执着,这些通配符在不同的语言中存在差别,就像 SQL 和正则引擎或多或少地存在兼容性问题一样。如果有朋友知道如何对这种日期形式进行转换,欢迎在博客中评论留言,再次谢谢大家。第二,使用内置函数 sorted()对数据进行排序,lambda 表达式使用起来非常棒,因为默认是升序排列地,而我们需要的是日期由近到远,所以这里选择了降序排列。

现在我们更新博客时的流程将发生变化,首先通过 hexo generatehexo g 命令生成博客,这样 Hexo 会为我们生成 content.json,然后我们执行这段 Python 脚本,就可以生成 REAMD.md 文件,这里我们将这个文件推送到 blog 分支。相对应地,我们修改 TravisCI 的脚本文件 .travis.yml 文件如下:

script:
  - hexo clean
  - hexo generate
  - cp README.md ./public/README.md

显然,这是告诉 TravisCI 在生成博客以后,将 README.md 文件复制到输出文件,这样当我们推送博客(指生成的静态页面)到 master 分支的时候,它会和 blog 分支同步共享同一份 README 。我想一定有朋友会问我,难道生成 README.md 文件的步骤不能交给 TravisCI 来处理?一定要在推送到 blog 分支以前手动地去执行脚本吗?我最初尝试过让 TravisCI 去执行这个 Python 脚本,可我发现一个残酷的事实时,我们这个虚拟机环境是 nodejs 的,这在我们定义 .travis.yml 文件时就指定了,因此这个环境中可能是没有 Python 支持的。起初我以为 Linux 系统自带 Python , 因此尝试在 .travis.yml 文件中使用 pip 安装相关依赖,然后我发现持续集成服务华丽丽地挂了,因为 TravisCI 默认的 Python 版本是 Python2.7 , 除非我们指定的是一个 Python 的语言环境,所以这种想法不得不作罢,暂时就手动更新好啦。

好了,这篇文章核心的内容就这么多,下面想说些关于 Hexo 的延伸话题。 Hexo 是一个基于 nodejs 的静态博客生成器,按理说使用 nodejs 去扩展功能是最佳的实践方式,所以即使 Python 再强大,我们在这里看到的依然存在着天然的割裂感, 我们能不能将执行 Python 脚本的这个过程合并到 hexo generate 或者 hexo g 这个步骤中去呢? 通过官方文档中关于事件生成器的描述,我们获得了两种新的思路,分别是在生成页面以后通过 child_process 模块调用 python 脚本、通过 Locals 变量获取全部文章信息后生成 Markdown。从方案是否优雅的角度上来讲,我个人更倾向于第二种方案。基本的代码如下:

//方案一
hexo.on('generateAfter', function(post){
  //TODO:通过content.json文件生成markdown文档
});

//方案二
hexo.extend.generator.register("markdown", function(locals){
  var posts = locals.posts;
  //TODO:通过posts属性生成markdown文档
});

显然,我是不会写 nodejs 的,如果有时间和精力的话,我可能会考虑采用第二种方案写一个插件,可是像我这么懒的一个人,还是不要提前立 flag 啦,毕竟人生苦短呐,我都选择使用 Python 这门语言来写啦,我干嘛非要再花时间去迎合它呢?好啦,这篇文章就是这样啦,本文中的脚本可以到 这里 来获取,本文生成的目录可以到 这里 来访问,再次谢谢大家!