- 前端
- 文档
【免费下载链接】academicpages.github.io
Github Pages template based upon HTML and Markdown for personal, portfolio-based websites.
本文聚焦 academicpages.github.io 仓库中
markdown_generator/目录的内容生成工具链,系统讲解如何通过命令行 Python 脚本(publications.py、talks.py)和 Jupyter Notebook(publications.ipynb、talks.ipynb)将结构化的 TSV/CSV/BibTeX 数据批量转换为站点可直接渲染的 Markdown 文件。读完本文,你将掌握每种工具的输入数据格式、字段语义、命令行用法、底层实现原理,以及生成结果如何被站点的 Jekyll 集合(collections)与页面模板消费,从而搭建一条"表格数据 → 站点页面"的高效内容流水线。
一、目录概览:同一目标的两条路径
markdown_generator/目录的核心使命非常明确:把散落在电子表格或参考文献数据库里的结构化元数据,批量转换成 academicpages 模板能够直接消费的 Markdown 文件。仓库 README(markdown_generator/README.md)开宗明义地指出,这个目录提供了"各种创建站点 Markdown 的方法"。
目录内所有工具按文件类型分为两大类,二者功能高度对等,但使用场景不同:
| 文件类型 | 代表文件 | 运行方式 | 设计取向 |
|---|---|---|---|
.py脚本 | publications.py、talks.py、pubsFromBib.py | 命令行(如python3 publications.py publications.csv) | 依赖极少,便于在 GitHub Pages 构建环境中直接运行 |
.ipynb笔记本 | publications.ipynb、talks.ipynb、OrcidToBib.ipynb | Jupyter 逐单元交互执行 | 内置大量过程文档,适合交互式探索与调试 |
README 特别强调了.py脚本的设计初衷:"确保它们对第三方包的需求尽可能少,从而可以在 GitHub 部署站点时直接运行"。这一设计在源码中得到印证:talks.py顶部注释明确写着 "Uses the Python standard library (csv) so it has no external dependencies",而publications.py同样只导入csv、os、sys三个标准库模块——这意味着你不需要pip install任何东西,只要有 Python 3 解释器就能完成内容生成。
从数据源角度看,工具链覆盖三种输入形态:
- TSV/CSV 表格数据(
publications.tsv、talks.tsv、publications.csv)—— 面向出版物与演讲; - BibTeX 文献库(
pubsFromBib.py)—— 面向学术出版物; - ORCID 在线文献记录(
OrcidToBib.ipynb)—— 面向已关联 ORCID 账号的研究者。
二、命令行脚本:publications.py 出版物生成器
publications.py是出版物内容生成的核心脚本,其功能与文档注释(markdown_generator/publications.py)描述一致:"接收带元数据的 TSV/CSV 文件,转换为 academicpages 站点可用的 Markdown"。
2.1 命令行用法与校验逻辑
脚本只接受一个位置参数,且必须是.csv或.tsv结尾的文件:
python3 publications.py publications.csv # CSV 输入 python3 publications.py publications.tsv # TSV 输入入口代码(if __name__ == '__main__':)执行三层校验:
- 参数个数:
len(sys.argv) != 2时输出Usage: python3 publications.py [filename]并以非零码退出; - 扩展名:非
.csv/.tsv文件会被拒绝,提示Expected a TSV or CSV file; - 内容行数与表头:文件少于 2 行(仅表头或为空)时提示 "Not enough lines in the file to process";表头不匹配时报 "The header of the file does not match the expected format"。
分隔符的判定在read()函数中完成:文件名以.csv结尾用逗号,否则用制表符(delimiter = ',' if filename.endswith('.csv') else '\t'),因此talks.txt之类的文件也能按 TSV 规则解析。
2.2 数据格式:两代表头规范
脚本在源码中定义了两套表头(HEADER_LEGACY与HEADER_UPDATED),并自动兼容:
HEADER_LEGACY = ['pub_date', 'title', 'venue', 'excerpt', 'citation', 'url_slug', 'paper_url', 'slides_url'] HEADER_UPDATED = ['pub_date', 'title', 'venue', 'excerpt', 'citation', 'url_slug', 'paper_url', 'slides_url', 'category']两代格式的唯一区别是新增了category列(UPDATED 版)。read()会先检查首行是否等于HEADER_LEGACY,等于则按旧格式处理,否则要求必须完全匹配HEADER_UPDATED,否则报错退出。仓库中恰好同时提供了两种格式的样例:publications.tsv(8 列旧格式,3 条示例记录)与 publications.csv(9 列新格式,含category: manuscripts)。
各字段语义与约束如下(源自脚本头部文档注释与create_md()的实际处理逻辑):
| 字段 | 是否必填 | 约束与用途 |
|---|---|---|
pub_date | 必填 | 必须为YYYY-MM-DD格式;决定文件名前缀与 permalink 中的日期段 |
title | 必填 | 写入 front matter 的title |
venue | 必填 | 写入venue,经 HTML 转义 |
excerpt | 可空 | 长度超过 5 个字符时写入excerpt并出现在正文描述区 |
citation | 必填 | 写入citation,经 HTML 转义,渲染为"Recommended citation" |
url_slug | 必填 | 文件名与 permalink 的描述性段;文件名为YYYY-MM-DD-[url_slug].md,permalink 为/publication/YYYY-MM-DD-[url_slug] |
paper_url | 可空 | 长度超过 5 个字符时写入paperurl并生成 "Download paper here" 链接 |
slides_url | 可空 | 长度超过 5 个字符时写入slidesurl(注意:脚本新版未生成"Download slides"正文链接,但 front matter 会保留该字段) |
category | 仅新格式 | 写入category;旧格式统一回退为category: manuscripts |
2.3 HTML 转义:YAML 兼容性的关键设计
由于生成的 Markdown 头部是 YAML front matter,而 YAML 对字符串中的引号非常敏感,脚本定义了一张转义表:
HTML_ESCAPE_TABLE = { "&": "&", '"': """, "'": "'" }html_escape()函数会逐字符替换三个特殊字符。正如注释所说:"这让原始文件看起来不那么易读,但解析后渲染效果很好"。这一点在样例输出中可以直接验证:2009-10-01-paper-title-number-1.md 中citation字段的值是'Your Name, You. (2009). "Paper Title Number 1." <i>Journal 1</i>. 1(1).'——双引号被转义为",在浏览器中会正确还原为普通引号。
2.4 生成逻辑:create_md() 逐行拼装
create_md(lines, layout)是"真正干重活的地方"(脚本注释原文)。它遍历每一行数据,依次拼装:
- 文件名与 HTML 文件名:
md_filename = f"{pub_date}-{url_slug}.md"; - YAML 头部:依次写入
title、collection: publications、category(旧格式为manuscripts)、permalink: /publication/{html_filename}、可选excerpt、date、venue、可选paperurl、citation; - 正文区:可选的 "Download paper here" 链接、可选 excerpt 文本、
Recommended citation: ...; - 落盘:
md_filename = os.path.join("../_publications/", os.path.basename(md_filename)),即输出到仓库根目录下的_publications/文件夹。
值得注意的实现细节:paper_url与excerpt的判空阈值是长度大于 5(len(str(item)) > 5),这是为了过滤 NaN 之类的空值残留。
三、命令行脚本:talks.py 演讲与教程生成器
talks.py与publications.py是同族工具,但针对演讲(talks)场景做了独立设计,且接口更灵活。
3.1 命令行用法
python3 talks.py talks.tsv # 输出到默认目录 ../_talks/ python3 talks.py talks.tsv _talks/ # 自定义输出目录 python3 talks.py talks.csv # CSV 输入同样支持脚本把"输入文件"与"输出目录"解耦:不传输出目录时,默认取脚本所在目录的上级_talks(os.path.join(script_dir, "..", "_talks")),并自动执行os.makedirs(output_dir, exist_ok=True)确保目录存在。
3.2 数据格式
talks.tsv(markdown_generator/talks.tsv)的完整表头为:title, type, url_slug, venue, date, location, talk_url, description。仓库自带 4 条示例记录,覆盖了Talk、Tutorial、Conference proceedings talk三种类型,正好用来演示type字段的多样性。
字段规则(源自脚本实现与 talks.ipynb 的文档说明):
- 必填字段只有三个:
title、url_slug、date。任一缺失时脚本会打印 "Skipping row: missing required field (title, url_slug, or date)" 并跳过该行; date必须为YYYY-MM-DD,且date与url_slug的组合必须唯一——它是文件名与 permalink 的基础;type为空或过短(len(talk_type) > 3判断)时,回退为默认值"Talk";venue、location为空则不写入对应 YAML 字段;talk_url非空时在正文生成More information here链接;description非空时写入正文,并经 HTML 转义。
3.3 实现差异
与publications.py相比,talks.py有两个显著特点:
- 使用
csv.DictReader按列名取值,而非按索引位置,代码可读性更好; - 显式声明零外部依赖("Uses the Python standard library (csv) so it has no external dependencies"),并统一用
encoding="utf-8"读写,对中文内容更友好。
它生成的 front matter 结构可从仓库已有的生成结果验证,例如 _talks/2012-03-01-talk-1.md:
--- title: "Talk 1 on Relevant Topic in Your Field" collection: talks type: "Talk" permalink: /talks/2012-03-01-talk-1 venue: "UC San Francisco, Department of Testing" date: 2012-03-01 location: "San Francisco, CA, USA" ---四、Jupyter Notebook 路径:交互式生成流程
如果更喜欢可视化、可逐步调试的工作方式,publications.ipynb与talks.ipynb提供了完整交互路径。两个笔记本都遵循同一套流程模板:
!cat查看原始 TSV:先展示数据形态,并说明"原始文件不美观,建议用电子表格编辑";import pandas as pd:引入 pandas,用pd.read_csv("xxx.tsv", sep="\t", header=0)读取数据。笔记本文档特别解释了为什么选 TSV 而非 CSV:"这类数据里包含大量逗号,逗号分隔容易被搞乱";同时提示可以替换为read_excel()、read_json()等读取其他格式;- 定义
html_escape转义函数:与脚本版同一套转义表,talks.ipynb版额外做了isinstance(text, str)类型判断; iterrows()逐行拼装 Markdown:核心逻辑与脚本版一致,但publications.ipynb版还额外生成了slidesurlfront matter 字段和 "[Download slides here]" 正文链接,并计算了year = item.pub_date[:4](脚本版未使用);- 写入
../_publications/或../_talks/,最后用!ls与!cat展示生成结果。
笔记本内置的完整执行输出(如!cat ../_publications/2009-10-01-paper-title-number-1.md的完整结果)本身就是最好的教程素材,可以直接对照学习 YAML front matter 的最终形态。
五、BibTeX 路径:pubsFromBib.py 与 OrcidToBib.ipynb
5.1 pubsFromBib.py:从 BibTeX 批量生成
对于科研人员,文献通常已经积累在.bib文件中。pubsFromBib.py 基于pybtex库实现 BibTeX → Markdown 的转换,是上述 TSV 路径之外的重要补充(源码注释中明确标注了 TODO:"Merge this with the existing TSV parsing solution")。
核心设计是publist配置字典,按文献类型定义解析规则:
publist = { "proceeding": { "file": "proceedings.bib", "venuekey": "booktitle", "venue-pretext": "In the proceedings of ", "collection": {"name": "publications", "permalink": "/publication/"} }, "journal": { "file": "pubs.bib", "venuekey": "journal", "venue-pretext": "", "collection": {"name": "publications", "permalink": "/publication/"} } }每个键对应一个 BibTeX 文件,venuekey指定从哪个字段取 venue(会议是booktitle,期刊是journal),venue-pretext是 venue 前置文本。运行前需按自己的 bib 文件名、venue 键和个性化前置文本修改该字典。
处理流程(for pubsource in publist:循环内):
- 用
pybtex解析 bib 文件,遍历每条bib_id; - 日期归一化:默认
1900-01-01,从year/month/day字段组装YYYY-MM-DD,其中月份做了数字与英文缩写(strptime(b["month"][:3],'%b'))的兼容处理; - url_slug 生成:对标题做
{}、\、空格清理后,用正则re.sub("\\[.*\\]|[^a-zA-Z0-9_-]", "", clean_title)剔除非法字符,并合并连续--; - citation 自动拼装:作者(
persons["author"]的 first/last name)+ 标题 + venue 前置文本 + venue + 年份; - YAML 生成:
title、collection、permalink、可选excerpt(来自 bib 的note字段)、date、venue、可选paperurl(来自 bib 的url字段)、citation; - 正文生成:有
note则输出;有url则输出Access paper here{:target="_blank"},否则输出一条指向 Google Scholar 搜索的兜底链接; - 异常处理:缺字段的条目捕获
KeyError,打印WARNING Missing Expected Field ...并跳过,不中断整体流程。
5.2 OrcidToBib.ipynb:从 ORCID 拉取文献
OrcidToBib.ipynb 是流水线的"数据获取前端":它调用 ORCID 公共 API(https://pub.orcid.org/v3.0/{orcid}/works,请求头Accept: application/orcid+json)列出某 ORCID 账号的全部作品,收集每个作品的put-code;再逐条请求/{orcid}/work/{put-code}端点取回完整引文信息(work['citation']['citation-value']),最后把所有引文写入output.bib。生成的.bib再交给pubsFromBib.py消费,即可打通"ORCID → BibTeX → 出版物 Markdown"的完整链路。
六、生成结果如何被站点消费
理解生成器的价值,需要看到它在整个站点模板中的位置——生成器输出的 Markdown 正是 Jekyll 集合与页面模板的输入。
6.1 集合(collections)定义
_config.yml 中声明了四个集合,其中publications与talks与生成器直接对应:
collections: publications: output: true permalink: /:collection/:path/ talks: output: true permalink: /:collection/:path/output: true意味着_publications/与_talks/下的每个 Markdown 文件都会渲染为独立页面。同文件后半段的defaults配置为publications类型指定layout: single,为talks类型指定layout: talk,并统一开启author_profile与share。
6.2 归档页如何取用生成数据
_pages/publications.html 展示了生成数据在归档页的两种消费方式:
- 若
_config.yml中定义了site.publication_category,则按post.category分组,为每个分类渲染独立标题区块(这正是新表头category字段的用武之地); - 否则直接
{% for post in site.publications reversed %}遍历全部出版物,通过archive-single.html渲染列表项。
_pages/talks.html 则更简单:{% for post in site.talks reversed %}遍历_talks/下所有生成文件,用archive-single-talk.html渲染;若_config.yml中talkmap_link: true,还会在页首追加 talkmap 地图入口链接。
6.3 单页模板
_layouts/talk.html会渲染page.talk_type、page.venue、page.location、page.date等字段——这些正是talks.py写入 front matter 的键名,字段命名的一致性保证了生成文件无需任何手工改动即可被模板正确展示。
七、选型建议与工作流总结
结合 README 说明与源码实现,可以给出如下选型参考:
| 场景 | 推荐工具 | 理由 |
|---|---|---|
| 本地批量生成出版物 | python3 publications.py publications.tsv | 零依赖、可脚本化、自动校验表头 |
| 本地批量生成演讲 | python3 talks.py talks.tsv | 零依赖、支持自定义输出目录、缺字段自动跳过 |
| 交互式探索与调试 | publications.ipynb/talks.ipynb | 单元格可视化、内置文档与示例输出 |
| 已有 BibTeX 文献库 | pubsFromBib.py | 自动生成 citation 与 url_slug |
| 有 ORCID 账号 | OrcidToBib.ipynb→pubsFromBib.py | 全自动拉取并转换 |
最小可行工作流:用电子表格维护publications.tsv(或talks.tsv)→ 保存为 TSV → 在markdown_generator/目录执行对应 Python 脚本 → 检查_publications/(或_talks/)下新生成的.md文件 → 提交仓库,GitHub Pages 构建时由 Jekyll 自动渲染为出版物/演讲页面。整个过程不需要安装任何第三方 Python 包,也不需要手工编写任何 front matter。
最后提醒两点使用边界:一是publications.py的category是 9 列新表头才支持的字段,旧 8 列格式会统一回退为manuscripts;二是pubsFromBib.py依赖pybtex第三方库,且publist字典需要按自己的 bib 文件调整,与"零依赖"的 TSV 脚本适用场景不同。按需选择,即可把内容维护的重心从"手写 Markdown"转移到"维护一张干净的表格"上。
- 前端
- 文档
【免费下载链接】academicpages.github.io
Github Pages template based upon HTML and Markdown for personal, portfolio-based websites.
相关推荐
academicpages 演讲(Talks)页面实战指南:从 Front Matter 字段到批量生成与地图展示
academicpages 演讲(Talks)页面实战指南:从 Front Matter 字段到批量生成与地图展示 本指南围绕 \_talks/2012 03
前端文档Jupytext 实战指南:把 Jupyter Notebook 变成可版本控制的 Markdown、Python 与 R 文本文件
Jupytext 实战指南:把 Jupyter Notebook 变成可版本控制的 Markdown、Python 与 R 文本文件 Jupytext 是一个让
开发工具使用 SumatraPDF 内置的 mutool create:从内容流脚本批量生成 PDF
使用 SumatraPDF 内置的 mutool create:从内容流脚本批量生成 PDF 导读 mutool create 是 MuPDF 工具集中用于“从
桌面应用文档
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考