用 Python + Ollama 搭建博客文章自动生成器,从选题到成稿一键完成,支持多风格和排版输出。
你有没有这种痛苦:想写博客,但选题选半天,大纲理不清,动笔写又卡壳,最后文章拖了两周还没发出去。
手动写太慢,AI 代写又怕查重。今天做一个批量博客文章生成器。选题→大纲→撰写→排版,全程自动化,本地跑,不花一分钱。
项目背景
个人博客需要持续更新,但写作是最耗时的环节。用 AI 辅助写作已经很常见,但大多数人只用 ChatGPT 问一个问题,生成一篇就停了。
真正的痛点是:批量生成、风格统一、自动排版、多渠道发布。
这个项目要解决的就是这些问题。用 Python 脚本 + 本地 LLM,实现从选题到发布的完整工作流。
技术选型
| 组件 | 选择 | 理由 |
|---|---|---|
| 写作引擎 | Ollama + LLaMA 3 | 本地运行,无网络依赖 |
| 选题库 | 手动维护 + 随机抽样 | 控制内容质量 |
| 大纲生成 | 结构化 prompt | 保证文章结构 |
| 撰写模块 | 分步生成 | 控制质量和长度 |
| 输出格式 | Markdown + Hugo 页面 | 直接发布 |
| 风格控制 | 模板 + 参数 | 统一博客调性 |
Ollama 安装:
curl -fsSL https://ollama.com/install.sh | sh
ollama pull llama3:8b
实现步骤
第一步:项目结构
mkdir -p blog_generator/{topics,outline,drafts,final}
cd blog_generator
touch generator.py config.yaml topics.txt
目录说明:
topics/— 选题库,每个文件一个主题outline/— 生成的文章大纲drafts/— 撰写草稿final/— 最终发布稿
第二步:配置文件 config.yaml
model: llama3:8b
temperature: 0.7
max_tokens: 2000
blog_style:
tone: 技术教程
audience: 开发者
language: zh
length: 中等
output:
format: markdown
include_toc: true
tag_style: comma
prompt_templates:
topic_selection: |
你是一个博客内容策划。根据以下主题方向,生成5个具体的文章选题。
要求:适合技术博客,有实际价值,标题吸引人。
主题方向:{topic_direction}
outline_generation: |
为以下标题生成博客文章大纲。
要求:包含引言、3-5个主要章节、总结。
标题:{title}
article_draft: |
根据以下大纲撰写完整博客文章。
风格:{tone}
目标读者:{audience}
要求:实用性强,代码示例丰富,字数800-1500。
大纲:
{outline}
第三步:选题库 topics.txt
# 格式:标题 | 方向标签 | 关键词
AI模型本地部署 | 技术教程 | ollama,本地LLM
Python自动化脚本 | 效率工具 | python,自动化,crontab
博客内容运营 | 运营技巧 | 博客,SEO,写作
Web开发实战 | 技术教程 | flask,fastapi,前端
数据可视化 | 数据分析 | matplotlib,可视化
第四步:核心生成器 generator.py
#!/usr/bin/env python3
"""AI 博客文章批量生成器"""
import os
import yaml
import random
import subprocess
from pathlib import Path
from datetime import datetime
import json
# ============ 配置加载 ============
def load_config():
with open("config.yaml", encoding="utf-8") as f:
return yaml.safe_load(f)
CFG = load_config()
MODEL = CFG["model"]
# ============ 工具函数 ============
def ollama_generate(prompt, max_tokens=2000):
"""调用 Ollama 生成内容"""
result = subprocess.run(
["ollama", "run", MODEL, prompt],
capture_output=True,
text=True,
timeout=120
)
return result.stdout.strip()
def read_topics():
"""读取选题库"""
topics = []
if Path("topics.txt").exists():
with open("topics.txt", encoding="utf-8") as f:
for line in f:
line = line.strip()
if line and not line.startswith("#"):
parts = line.split("|")
if len(parts) >= 3:
topics.append({
"title": parts[0].strip(),
"tag": parts[1].strip(),
"keywords": parts[2].strip()
})
return topics
def save_file(content, filepath):
"""保存文件"""
Path(filepath).parent.mkdir(parents=True, exist_ok=True)
with open(filepath, "w", encoding="utf-8") as f:
f.write(content)
print(f" ✅ 已保存: {filepath}")
# ============ 生成步骤 ============
def generate_topic_selection(topic_direction):
"""生成选题建议"""
prompt = CFG["prompt_templates"]["topic_selection"].format(
topic_direction=topic_direction
)
return ollama_generate(prompt)
def generate_outline(title, style_cfg):
"""生成文章大纲"""
prompt = CFG["prompt_templates"]["outline_generation"].format(title=title)
return ollama_generate(prompt)
def generate_article(outline, style_cfg):
"""撰写完整文章"""
prompt = CFG["prompt_templates"]["article_draft"].format(
tone=style_cfg["tone"],
audience=style_cfg["audience"],
outline=outline
)
return ollama_generate(prompt, max_tokens=CFG["max_tokens"])
def add_frontmatter(title, tags, date=None):
"""添加 Hugo frontmatter"""
if date is None:
date = datetime.now().strftime("%Y-%m-%d")
tags_str = ", ".join(tags) if isinstance(tags, list) else tags
frontmatter = f"""---
title: "{title}"
date: {date}
description: ""
tags: [{tags_str}]
draft: false
---
"""
return frontmatter
def generate_slug(title):
"""生成 URL slug"""
import re
title = title.lower()
title = re.sub(r'[^\w\s-]', '', title)
title = re.sub(r'[\s]+', '-', title)
return title.strip('-')
# ============ 主流程 ============
def generate_one_article(topic):
"""生成单篇文章"""
title = topic["title"]
print(f"\n📝 生成文章: {title}")
# 步骤1: 生成大纲
print(" 📋 生成大纲...")
outline = generate_outline(title, CFG["blog_style"])
outline_path = f"outline/{generate_slug(title)}.txt"
save_file(outline, outline_path)
# 步骤2: 撰写文章
print(" ✍️ 撰写文章...")
article = generate_article(outline, CFG["blog_style"])
draft_path = f"drafts/{generate_slug(title)}.md"
save_file(article, draft_path)
# 步骤3: 添加 frontmatter 和排版
print(" 📄 生成最终版本...")
tags = [topic["tag"]] + topic["keywords"].split(",")
frontmatter = add_frontmatter(title, tags)
final_content = frontmatter + "\n" + article
final_path = f"final/{generate_slug(title)}.md"
save_file(final_content, final_path)
return {
"title": title,
"slug": generate_slug(title),
"outline": outline_path,
"draft": draft_path,
"final": final_path
}
def generate_batch(count=3, random_topic=None):
"""批量生成文章"""
topics = read_topics()
if not topics:
print("⚠️ 选题库为空,请先编辑 topics.txt")
return
print(f"📚 共 {len(topics)} 个选题")
print(f"🎯 本次生成 {count} 篇文章")
if random_topic:
selected = [random.choice(topics)]
else:
selected = random.sample(topics, min(count, len(topics)))
results = []
for topic in selected:
try:
result = generate_one_article(topic)
results.append(result)
except Exception as e:
print(f" ❌ {topic['title']}: {e}")
print(f"\n🎉 完成!成功生成 {len(results)} 篇文章")
return results
def add_new_topic(title, tag, keywords):
"""手动添加选题"""
line = f"{title} | {tag} | {keywords}\n"
with open("topics.txt", "a", encoding="utf-8") as f:
f.write(line)
print(f"✅ 已添加选题: {title}")
# ============ CLI 入口 ============
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("用法:")
print(" python generator.py batch [数量] # 批量生成")
print(" python generator.py single # 随机生成一篇")
print(" python generator.py add <标题> <标签> <关键词>")
print(" python generator.py list # 查看选题库")
sys.exit(1)
cmd = sys.argv[1]
if cmd == "batch":
count = int(sys.argv[2]) if len(sys.argv) > 2 else 3
generate_batch(count)
elif cmd == "single":
generate_batch(1)
elif cmd == "add":
if len(sys.argv) < 5:
print("用法: python generator.py add <标题> <标签> <关键词>")
sys.exit(1)
add_new_topic(sys.argv[2], sys.argv[3], sys.argv[4])
elif cmd == "list":
topics = read_topics()
print(f"选题库(共 {len(topics)} 个):")
for i, t in enumerate(topics, 1):
print(f" {i}. {t['title']} [{t['tag']}]")
else:
print(f"未知命令: {cmd}")
第五步:运行测试
# 查看选题库
python generator.py list
# 批量生成3篇文章
python generator.py batch 3
# 添加新选题
python generator.py add "AI编程助手对比" "技术评测" "cursor,claude,chatgpt"
# 随机生成一篇
python generator.py single
生成的文章直接放到 Hugo 的 content/blog/ 目录就能发布。
运行效果
生成完成后目录结构:
blog_generator/
├── topics.txt # 选题库
├── config.yaml # 配置文件
├── generator.py # 生成器
├── outline/ # 大纲文件
│ └── ai-model-local-deployment.txt
├── drafts/ # 草稿
│ └── ai-model-local-deployment.md
└── final/ # 最终发布稿
└── ai-model-local-deployment.md
最终文件内容示例:
---
title: "AI模型本地部署完全指南"
date: 2026-08-09
description: ""
tags: [技术教程, ollama, 本地LLM]
draft: false
---
# AI模型本地部署完全指南
...(文章内容)...
优化方向
- 自动发布:生成后自动 commit 到 Git,触发 CI/CD
- 配图生成:用 Stable Diffusion 自动生成文章配图
- SEO 优化:自动分析关键词密度,给出优化建议
- 多语言支持:配置 LANGUAGE 参数,一键生成英文版本
- 风格学习:读取历史文章,模仿已有风格
- 定时发布:配合 crontab,每天自动生成并发布
批量生成只是第一步,真正有价值的是持续产出。你的博客现在多久更新一次?
下一步:把生成的文章复制到 content/blog/,运行 hugo 构建,就能看到效果了。
这篇文章对你有帮助吗?