核心概念与工作流程
我们需要理解一个基于 Markdown 的静态博客是如何工作的:

- 内容创作:你使用任何文本编辑器(如 VS Code, Typora)编写
.md(Markdown) 文件。 - 元数据:在
.md文件的开头,使用一种叫做 Front Matter 的格式(通常是 YAML)来存放文章的元数据,比如标题、日期、标签等。--- "我的第一篇博客" date: "2025-10-27" tags: ["Python", "Markdown"] ---
- 构建/渲染:Python 脚本会读取所有
.md文件,解析 Front Matter,然后将 Markdown 内容转换成 HTML。 - 模板引擎:生成的 HTML 片段会被“套入”一个预先设计好的 HTML 模板中,就像把蛋糕胚放进漂亮的蛋糕盒里一样,最终形成一个完整的网页。
- 静态站点生成:所有生成的 HTML 文件、CSS 样式表、JavaScript 脚本和图片资源会被组合在一起,生成一个完整的、可以直接在服务器上运行的静态网站。
工作流程图:
[你的 .md 文件] --(Python 脚本解析)--> [HTML 片段] --(套入模板)--> [HTML 网站]
技术选型
为了实现上述流程,我们需要一些 Python 庑:
- Markdown 解析器:将
.md文本转为 HTML。Mistune:速度快,功能强大。Markdown:Python 标准库自带,简单易用。Python-Markdown:功能全面,可扩展性好。
- 模板引擎:将 HTML 片段和模板结合。
Jinja2:功能强大,语法灵活,是 Flask/Django 框架的默认选择,强烈推荐。
- Front Matter 解析器:解析文件头部的 YAML 数据。
python-frontmatter:轻量且专门用于此任务。
- 可选 - 命令行工具:方便地运行构建脚本。
Click:创建用户友好的命令行接口。
- 可选 - 静态文件服务器:本地预览你的博客。
Python 内置的http.server`:简单快捷。
项目搭建与代码实现
我们将从头开始构建一个极简但功能完整的静态博客生成器。
步骤 1:项目结构
一个清晰的项目结构至关重要,建议如下:

my_blog/
├── content/ # 存放你的所有 Markdown 文章
│ ├── my-first-post.md
│ └── another-post.md
├── templates/ # 存放 HTML 模板
│ ├── base.html # 基础模板,包含公共部分
│ ├── index.html # 首页模板
│ └── post.html # 文章详情页模板
├── static/ # 存放 CSS, JS, 图片等静态资源
│ └── style.css
├── output/ # 构建完成后生成的网站(通常可忽略)
├── build.py # 我们的核心 Python 构建脚本
└── requirements.txt # 项目依赖
步骤 2:安装依赖
创建 requirements.txt 文件,内容如下:
Jinja2
python-frontmatter
Markdown
然后安装它们:
pip install -r requirements.txt
步骤 3:编写内容和模板
创建一篇文章
在 content/ 目录下创建 hello-world.md:

--- "你好,世界!"
date: "2025-10-27"
tags: ["介绍", "Python"]
---
# 这是一篇博客文章
内容,我们可以使用标准的 Markdown 语法。
* 这是列表项一
* 这是列表项二
你可以使用 **粗体** 和 *斜体*。
```python
# 代码块
def hello():
print("Hello from my blog!")
**2. 创建基础模板**
在 `templates/` 目录下创建 `base.html`,这是所有页面的“外壳”:
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">{% block title %}我的 Python 博客{% endblock %}</title>
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<header>
<h1><a href="/">我的 Python 博客</a></h1>
</header>
<nav>
<!-- 未来可以添加链接 -->
</nav>
<main>
{% block content %}{% endblock %}
</main>
<footer>
<p>© 2025 我的博客</p>
</footer>
</body>
</html>
创建首页模板
在 templates/ 目录下创建 index.html,用于显示所有文章列表:
{% extends "base.html" %}
{% block title %}首页 - {{ super() }}{% endblock %}
{% block content %}
<h2>所有文章</h2>
<ul>
{% for post in posts %}
<li>
<a href="{{ post.url }}">{{ post.title }}</a> -
<small>{{ post.date }}</small>
</li>
{% else %}
<li>暂无文章</li>
{% endfor %}
</ul>
{% endblock %}
创建文章详情页模板
在 templates/ 目录下创建 post.html,用于显示单篇文章:
{% extends "base.html" %}
{% block title %}{{ post.title }} - {{ super() }}{% endblock %}
{% block content %}
<article>
<h1>{{ post.title }}</h1>
<p class="post-meta">
发布于: {{ post.date }} | 标签: {{ post.tags|join(', ') }}
</p>
<div class="post-content">
{{ post.html_content|safe }}
</div>
</article>
{% endblock %}
注意:
|safe是 Jinja2 的一个过滤器,它告诉模板引擎这个 HTML 内容是安全的,不要进行转义。
创建一个简单的 CSS
在 static/ 目录下创建 style.css,给博客加点样式:
body { font-family: sans-serif; line-height: 1.6; margin: 0; padding: 20px; background-color: #f4f4f4; }
header { background: #333; color: #fff; padding: 10px 0; text-align: center; }
header h1 a { color: #fff; text-decoration: none; }
main { background: #fff; padding: 20px; margin: 20px auto; max-width: 800px; border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.1); }
footer { text-align: center; margin-top: 20px; color: #777; }
.post-meta { color: #666; font-size: 0.9em; }
code { background-color: #eee; padding: 2px 4px; border-radius: 3px; }
步骤 4:编写核心构建脚本 (build.py)
这是整个项目的“大脑”,在项目根目录下创建 build.py:
import os
import shutil
import markdown
from frontmatter import load
from jinja2 import Environment, FileSystemLoader
import click
# --- 配置 ---
CONTENT_DIR = 'content'
TEMPLATE_DIR = 'templates'
STATIC_DIR = 'static'
OUTPUT_DIR = 'output'
# --- 1. 初始化环境 ---
env = Environment(loader=FileSystemLoader(TEMPLATE_DIR))
# --- 2. 加载所有文章 ---
def load_posts():
"""加载 content 目录下的所有 markdown 文件,并解析为 Post 对象"""
posts = []
for filename in os.listdir(CONTENT_DIR):
if filename.endswith('.md'):
filepath = os.path.join(CONTENT_DIR, filename)
# 使用 frontmatter 加载,它会自动分离元数据和内容
post = load(filepath)
# 将 Markdown 内容转为 HTML
post.content = markdown.markdown(post.content, extensions=['fenced_code', 'codehilite'])
# 创建 URL 路径 (e.g., hello-world.html)
post.url = f"posts/{filename.replace('.md', '.html')}"
posts.append(post)
# 按日期降序排序
posts.sort(key=lambda p: p.date, reverse=True)
return posts
# --- 3. 渲染页面 ---
def render_pages(posts):
"""渲染所有页面并写入输出目录"""
# 清空输出目录
if os.path.exists(OUTPUT_DIR):
shutil.rmtree(OUTPUT_DIR)
os.makedirs(OUTPUT_DIR)
os.makedirs(os.path.join(OUTPUT_DIR, 'posts'))
shutil.copytree(STATIC_DIR, os.path.join(OUTPUT_DIR, 'static'))
# 渲染首页
index_template = env.get_template('index.html')
index_html = index_template.render(posts=posts)
with open(os.path.join(OUTPUT_DIR, 'index.html'), 'w', encoding='utf-8') as f:
f.write(index_html)
# 渲染每篇文章
post_template = env.get_template('post.html')
for post in posts:
post_html = post_template.render(post=post)
with open(os.path.join(OUTPUT_DIR, post.url), 'w', encoding='utf-8') as f:
f.write(post_html)
print(f"✅ 构建完成!网站已生成在 '{OUTPUT_DIR}' 目录。")
# --- 4. 命令行接口 ---
@click.command()
def build():
"""构建博客网站"""
posts = load_posts()
render_pages(posts)
if __name__ == '__main__':
build()
步骤 5:运行和预览
-
构建网站: 在项目根目录的终端中运行:
python build.py
你会看到
output目录被创建,里面包含了完整的静态网站。 -
本地预览: 为了方便查看,我们可以启动一个简单的 HTTP 服务器。
# 切换到输出目录 cd output # 启动 Python 内置的 HTTP 服务器 (Python 3) python -m http.server 8000
打开你的浏览器,访问
http://localhost:8000,就能看到你的博客首页了,点击文章链接,可以跳转到对应的详情页。
进阶与扩展
这个极简版本已经可以运行了,但一个真正的博客还需要更多功能,你可以在此基础上进行扩展:
-
标签和分类:
- 修改
load_posts()函数,收集所有唯一的标签。 - 创建一个新的模板
tag.html。 - 在
build.py中添加一个渲染标签页面的函数。 - 在首页和文章页的标签上添加链接。
- 修改
-
文章摘要:
- 在 Front Matter 中添加
summary字段。 - 在首页模板中,如果文章有
summary,则显示摘要,否则截取文章的前 N 个字符。
- 在 Front Matter 中添加
-
草稿模式:
- 在文件名或 Front Matter 中添加一个
draft: true标记。 - 在
load_posts()函数中,过滤掉draft为True的文章。
- 在文件名或 Front Matter 中添加一个
-
URL 结构:
- 使用文章的日期和标题来生成更友好的 URL,
/posts/2025/10/27/hello-world.html,这需要你在build.py中处理文件名和路径。
- 使用文章的日期和标题来生成更友好的 URL,
-
使用成熟的框架:
- 如果你觉得从零开始构建太复杂,可以考虑使用现成的 Python 静态博客生成器,它们已经为你处理了所有复杂逻辑:
- Pelican:功能非常强大,插件生态丰富,是 Python 社区最流行的选择之一。
- Nikola:同样功能强大,支持从 WordPress 导入等。
- Lektor:轻量级,易于使用,内置了简单的管理后台。
- 如果你觉得从零开始构建太复杂,可以考虑使用现成的 Python 静态博客生成器,它们已经为你处理了所有复杂逻辑:
通过这个指南,你已经掌握了使用 Python 和 Markdown 构建博客的核心原理和基本实现,虽然它很简单,但它清晰地展示了静态站点生成的工作方式,为你以后深入学习 Pelican 或其他工具打下了坚实的基础,最重要的是,你可以完全控制自己的网站,享受从内容创作到代码实现的全过程!
