py2htmlblog 使用指南

从安装到写文章、构建、切换主题的完整流程。

1. 环境要求

  • Python 3.7+
  • (可选)PyQt5 — 用于 GUI 界面:pip install PyQt5
  • (可选)paramiko — 用于 SFTP 发布:pip install paramiko

2. 初始化站点

python main.py init "我的博客" "https://example.com" "作者名"

这会在 data/ 下创建 info.json、category.json、links.json 三个配置文件,并在 templates/default/ 下复制默认模板。

3. 配置站点

编辑 data/info.json,设置站点基本信息:

{
  "site_name": "我的博客",
  "tagline": "记录生活与技术",
  "description": "一个有趣的个人博客",
  "site_url": "https://example.com",
  "author": "作者名",
  "language": "zh-CN",
  "timezone": "Asia/Shanghai",
  "template": "default",
  "posts_per_page": 10,
  "rss_count": 20,
  "copyright": "Copyright 2026",
  "nav_pages": [
    {"title": "首页", "url": "index.html"},
    {"title": "归档", "url": "archives.html"}
  ]
}

详细配置项见:data/info.json 字段说明

4. 管理分类

# 添加分类
python main.py add cat "日志" --slug log
python main.py add cat "技术" --slug tech
python main.py add cat "生活" --slug life

# 查看分类
python main.py list cats

# 删除分类(用 ID)
python main.py del cat 2

5. 写文章

方式一:命令行新建

python main.py new "我的第一篇文章" --cat log --tags "博客,Python"

然后输入文章正文(Markdown),输入 EOF 结束。

或者从文件导入正文:

python main.py new "文章标题" --cat tech --file article.md

方式二:mdblog 批量发布

把写好的 Markdown 文件放到 mdblog/ 目录,文件格式如下:

---
title: 文章标题
category: tech
tags: python,教程
datetime: 2026-07-22 17:30:00
slug: article-slug
---
正文内容(Markdown)...

然后运行:

python main.py publish

系统会自动分配 ID、生成 slug、保存到 data/post/ 并立即构建站点。

方式三:GUI 编辑器

python main.py gui

使用 PyQt 桌面编辑器,支持 Markdown 实时预览、分类管理、文章管理。

文章 frontmatter 完整字段

---
id: 1
title: 域名和空间
datetime: 2014-03-15 09:15:08
slug: yu-ming-he-kong-jian
category: log
tags: 域名, 空间
quotes: 几个域名和空间要到期
nearaid: 2
status: published
---
正文内容...
字段 必填 说明
id 否 文章 ID(自动分配时不填)
title 是 文章标题
datetime 否 发布时间,默认当前时间
slug 否 URL 别名,留空自动生成
category 是 分类的 slug
tags 否 标签,逗号分隔
quotes 否 引用/摘要
nearaid 否 关联文章 ID
status 否 published 或 draft

6. 构建站点

python main.py build

构建过程:

站点: 我的博客
模板: default
文章: 10 篇
分类: 3 个
友链: 5 个
正在生成首页...
正在生成归档页...
正在生成分类页...
正在生成文章页...
正在生成月度归档页...
正在生成 RSS...
正在生成 sitemap.xml...
构建完成 → wwwroot/

生成的静态文件在 wwwroot/ 目录中,结构如下:

wwwroot/
├── index.html              # 首页
├── index_2.html            # 第 2 页(如果有多页)
├── archives.html           # 归档/关于页
├── rss.xml                 # RSS 2.0 订阅
├── sitemap.xml             # 搜索引擎站点地图
├── css/                    # 样式表
├── js/                     # 脚本
├── images/                 # 图片
└── archives/               # 归档目录
    ├── cat_log.html        # 分类页
    ├── cat_tech.html
    ├── 2014/03/entry_1.html # 文章页
    ├── 03-01-2014_03-31-2014.html  # 月度归档
    └── ...

7. 切换主题

在 data/info.json 中修改 template 字段:

{
  "template": "inove"
}

支持的模板名:default、inove、boxed、clean、georgiablue、gettysburg、lovingrey、macstripe、matrixcode、modernlines、orangepurple、plainblue、plainjane、rusty、slashdotclassic、titaniumgold、tpthin、trendy

主题支持 ZIP 压缩包形式,详见 ZIP 模板说明。

8. 发布站点

py2htmlblog 内置三种发布方式,配置一次之后一键部署。

方式一:FTP 上传

适合虚拟主机(如 Bluehost、HostGator 等)。

在 data/info.json 中添加:

"deploy": {
  "method": "ftp",
  "ftp": {
    "host": "ftp.example.com",
    "port": 21,
    "user": "username",
    "password": "your-password",
    "remote_dir": "/public_html/"
  }
}

运行:

python main.py deploy

方式二:SFTP 上传

适合 VPS 或云服务器。

"deploy": {
  "method": "sftp",
  "sftp": {
    "host": "123.45.67.89",
    "port": 22,
    "user": "root",
    "key_file": "~/.ssh/id_rsa",
    "remote_dir": "/var/www/html/"
  }
}

支持密码和密钥两种认证方式。如果使用密钥,设置 key_file 即可,留空 password。

方式三:Git 推送

适合 GitHub Pages、Gitee Pages、Coding Pages 等。

"deploy": {
  "method": "git",
  "git": {
    "remote": "origin",
    "branch": "main",
    "repo_dir": "D:/my-site-repo",
    "commit_message": "Site update"
  }
}

repo_dir 是你本地 Git 仓库的路径。发布时系统会:

  1. 清空仓库目录(保留 .git)
  2. 复制 wwwroot 文件进去
  3. 执行 git add -A && git commit && git push

模拟运行

不确定配置是否正确?先模拟运行看看会上传哪些文件:

python main.py deploy --dry-run

9. 其他命令

# 查看站点信息
python main.py info

# 修改站点信息
python main.py set site_name "新名称"
python main.py set posts_per_page 5

# 列出文章
python main.py list posts

# 管理友链
python main.py add link "GitHub" "https://github.com" --desc "代码托管"
python main.py del link 2
python main.py list links

# 删除文章
python main.py del post 5

附录

appendix-infojson

data/info.json 完整字段说明

字段 类型 默认值 说明
site_name string "My Blog" 站点名称
tagline string "" 副标题/标语
description string "" 站点描述(meta & RSS)
site_url string "http://localhost" 站点 URL
author string "" 作者名
author_email string "" 作者邮箱
language string "zh-CN" 语言
timezone string "Asia/Shanghai" 时区
template string "default" 模板名
nextpostid int 1 下一篇文章 ID
postsperpage int 10 首页每页文章数
rss_count int 20 RSS 条目数
copyright string "" 版权信息
comment_code string "" 评论系统 HTML 代码
footer_code string "" 页脚统计代码
nav_pages array [] 导航页面列表

appendix-zip-模板

ZIP 模板使用

模板可以打包为 ZIP 以节省空间。系统加载优先级:目录 > ZIP。

打包命令:

cd templates
zip -r boxed.zip boxed/

ZIP 内部结构:

boxed.zip
├── header.html
├── footer.html
├── index.html
├── entry.html
├── category.html
├── archives.html
├── month_archive.html
├── rss.xml
└── css/
    └── style.css

ZIP 首次使用时自动解压到 .workbuddy/template_cache/,后续检测 ZIP 修改时间自动刷新缓存。

appendix-模板语法

模板引擎语法速查

语法 说明 示例
{{ var }} 变量替换 {{ site_name }}
{{ obj.attr }} 属性访问 {{ p.title }}
`{{ var \ filter }}` 过滤器 `{{ p.content_html\ safe }}`
{% for x in list %}...{% endfor %} 循环 文章列表循环
{% if cond %}...{% endif %} 条件 分页判断
{% include "file.html" %} 引入子模板 header/footer

内置过滤器:safe(不转义 HTML)、escape、date:"%Y-%m-%d"、truncate:100、default:"值"、striptags、upper、lower、length

appendix-convert

ThingamaBlog 模板转换

使用 convertthingamatemplates.py 将 ThingamaBlog 原始模板转换为 py2htmlblog 格式:

python convert_thingama_templates.py

转换规则:

ThingamaBlog py2htmlblog
<$BlogTitle$> {{ site_name }}
<$EntryTitle$> {{ p.title }}
<$EntryBody$> `{{ p.content_html\ safe }}`
<$EntryPermalink$> {{ siteurl }}/{{ p.entryurl }}
... {% for p in page_posts %}...{% endfor %}
... {% for a in archives %}...{% endfor %}
... {% for c in categories %}...{% endfor %}