第10章 10.3 终极项目:仿掘金博客系统实战工具
🎯 开场:为什么你需要一个"仿掘金"项目?
上一章我们用 Laravel 搭了一套完整的 API 接口,返回了文章列表、作者信息、点赞数。你有没有想过:如果不用 PHP,纯 Python 能不能也做出类似的东西?
痛点来了: 你想做一个自己的博客站,数据从哪来?买服务器太贵,学框架太难,有没有一种方式能快速做出一个能跑的小工具,并且能真实读取和展示数据?
这一章我们就用 Python,从零开始搭建一个仿掘金博客的数据查询工具。学完你能:
- 用 Python 读取 JSON 文件模拟数据库
- 用 Flask 快速搭一个微型 API(不需要买服务器,本地跑)
- 做一个带搜索和排序的博客浏览小工具
全程代码可复制运行,不废话。
🧱 基础 25 分钟:Python 读取数据的正确姿势
10.3.1 JSON 文件:程序的"记事本"
是什么: JSON 就是一种人类能看懂、数据结构也能读懂的格式。你可以把它理解成分类清晰的购物\n\n
\n\n
\n\n清单——每一项有名字、有价格、有数量。
为什么要用: 很多 API 返回的数据都是 JSON 格式,学会读写 JSON,就等于拿到了数据的"万能钥匙"。
怎么用:
import json
# 模拟掘金文章数据
articles = [
{"id": 1, "title": "Python入门第一课", "author": "老王", "likes": 120},
{"id": 2, "title": "Flask框架快速上手", "author": "小李", "likes": 85},
{"id": 3, "title": "Redis缓存实战", "author": "老王", "likes": 200}
]
# 把数据存到文件里
with open("articles.json", "w", encoding="utf-8") as f:
json.dump(articles, f, ensure_ascii=False, indent=2)
print("数据已保存!")
运行后会在当前文件夹生成 articles.json 文件,内容长这样:
[
{"id": 1, "title": "Python入门第一课", "author": "老王", "likes": 120},
{"id": 2, "title": "Flask框架快速上手", "author": "小李", "likes": 85},
{"id": 3, "title": "Redis缓存实战", "author": "老王", "likes": 200}
]
这行在干嘛: json.dump() 把 Python 列表转成字符串,写入文件。就像把购物清单拍照发给别人。
10.3.2 读取 JSON:把文件变回数据
import json
# 从文件读取数据
with open("articles.json", "r", encoding="utf-8") as f:
articles = json.load(f)
# 打印第一篇文章
print(articles[0])
# 输出: {'id': 1, 'title': 'Python入门第一课', 'author': '老王', 'likes': 120}
这行在干嘛: json.load() 把文件内容读进来,还原成 Python 能用的列表。
10.3.3 列表推导式:数据过滤的"流水线"
是什么: 列表推导式是一种一行代码搞定数据过滤的写法。你可以把它想象成自助餐厅的流水线——菜从传送带过来,你只挑想要的放到盘子里。
为什么要用: 如果你有 1000 篇文章,想筛选出点赞超过 100 的,用普通循环要写 5 行,列表推导式 1 行搞定。
怎么用:
# 筛选点赞超过100的文章
popular = [a for a in articles if a["likes"] > 100]
print(popular)
# 输出: [{'id': 1, 'title': 'Python入门第一课', ...}, {'id': 3, 'title': 'Redis缓存实战', ...}]
这行在干嘛: 中括号里的逻辑是"对于 articles 里的每个 a,如果 a 的 likes 大于 100,就留下来"。
![配图说明:列表推导式工作流程图,输入[文章1, 文章2, 文章3...],输出过滤后的高赞文章]
10.3.4 Flask 微型框架:5 行代码搭一个 API
是什么: Flask 是一个轻量级的 Python Web 框架,小到只有你真正用到才生效的功能。想象成租房时的简易家具——不多不少,够用就好。
为什么要用: 你想做一个网页让别人访问,总不能手动返回 HTML 字符串吧?Flask 帮你处理路由和响应,专注写业务逻辑。
怎么用:
from flask import Flask, jsonify
import json
app = Flask(__name__)
@app.route("/api/articles")
def get_articles():
with open("articles.json", "r", encoding="utf-8") as f:
articles = json.load(f)
return jsonify(articles)
if __name__ == "__main__":
app.run(debug=True, port=5000)
保存为 app.py,运行后在浏览器打开 http://127.0.0.1:5000/api/articles,就能看到 JSON 数据了!
这行在干嘛: @app.route 装饰器声明了一个网址 /api/articles,访问这个地址就执行下面的函数。
🔥 实战 35 分钟:3 个递进项目
项目 1(5 分钟):本地文章浏览工具
目标: 读取 JSON 文件,把所有文章打印成易读的格式。
import json
def display_articles():
with open("articles.json", "r", encoding="utf-8") as f:
articles = json.load(f)
print("=" * 50)
print(f"📚 共有 {len(articles)} 篇文章")
print("=" * 50)
for article in articles:
print(f"\n标题: {article['title']}")
print(f"作者: {article['author']}")
print(f"点赞: {article['likes']} ❤️")
if __name__ == "__main__":
display_articles()
预期输出:
==================================================
📚 共有 3 篇文章
==================================================
标题: Python入门第一课
作者: 老王
点赞: 120 ❤️
标题: Flask框架快速上手
作者: 小李
点赞: 85 ❤️
标题: Redis缓存实战
作者: 老王
点赞: 200 ❤️
一句话解释: 读取文件后,用 for 循环遍历列表,逐行打印文章信息。
项目 2(15 分钟):带筛选功能的博客工具
目标: 支持按作者筛选、按点赞数排序。
import json
def filter_and_sort():
with open("articles.json", "r", encoding="utf-8") as f:
articles = json.load(f)
# 让用户选择筛选方式
print("请选择操作:")
print("1. 按作者筛选")
print("2. 按点赞数排序(从高到低)")
choice = input("请输入选项: ")
if choice == "1":
author_name = input("请输入作者名: ")
filtered = [a for a in articles if a["author"] == author_name]
print(f"\n📝 {author_name} 的文章:")
else:
filtered = sorted(articles, key=lambda x: x["likes"], reverse=True)
print(f"\n🔥 按点赞数排序:")
for a in filtered:
print(f" • {a['title']} (点赞: {a['likes']})")
if __name__ == "__main__":
filter_and_sort()
预期输出(输入 1 后再输入"老王"):
请选择操作:
1. 按作者筛选
2. 按点赞数排序(从高到低)
请输入选项: 1
请输入作者名: 老王
📝 老王 的文章:
• Python入门第一课 (点赞: 120)
• Redis缓存实战 (点赞: 200)
一句话解释: 用列表推导式筛选,用 sorted() 函数配合 lambda 实现自定义排序。
项目 3(15 分钟):完整的博客数据管理工具
目标: 组合前面的能力,做一个带菜单的小工具,支持查看、搜索、导出功能。
import json
DATA_FILE = "articles.json"
def load_articles():
with open(DATA_FILE, "r", encoding="utf-8") as f:
return json.load(f)
def save_articles(articles):
with open(DATA_FILE, "w", encoding="utf-8") as f:
json.dump(articles, f, ensure_ascii=False, indent=2)
def show_all():
articles = load_articles()
print(f"\n📚 共有 {len(articles)} 篇文章:")
for i, a in enumerate(articles, 1):
print(f" {i}. {a['title']} by {a['author']} ({a['likes']} ❤️)")
def search_by_keyword():
keyword = input("请输入搜索关键词: ")
articles = load_articles()
results = [a for a in articles if keyword.lower() in a["title"].lower()]
print(f"\n🔍 找到 {len(results)} 篇相关文章:")
for a in results:
print(f" • {a['title']}")
def export_to_md():
articles = load_articles()
with open("blog_export.md", "w", encoding="utf-8") as f:
f.write("# 我的博客文章列表\n\n")
for a in articles:
f.write(f"## {a['title']}\n")
f.write(f"- 作者:{a['author']}\n")
f.write(f"- 点赞:{a['likes']}\n\n")
print("✅ 已导出到 blog_export.md")
def main():
while True:
print("\n" + "=" * 40)
print("🎯 博客数据管理工具")
print("=" * 40)
print("1. 查看所有文章")
print("2. 搜索文章")
print("3. 导出为 Markdown")
print("4. 退出")
choice = input("请选择操作: ")
if choice == "1":
show_all()
elif choice == "2":
search_by_keyword()
elif choice == "3":
export_to_md()
elif choice == "4":
print("👋 再见!")
break
else:
print("⚠️ 无效选项,请重试")
if __name__ == "__main__":
main()
预期输出:
========================================
🎯 博客数据管理工具
========================================
1. 查看所有文章
2. 搜索文章
3. 导出为 Markdown
4. 退出
请选择操作: 1
📚 共有 3 篇文章:
1. Python入门第一课 by 老王 (120 ❤️)
2. Flask框架快速上手 by 小李 (85 ❤️)
3. Redis缓存实战 by 老王 (200 ❤️)
一句话解释: 把读取、筛选、导出功能封装成独立函数,通过 while 循环和用户交互串联起来。
💪 进阶 20 分钟:新手最容易踩的坑
坑 1:文件路径写错
# ❌ 错误示例:相对路径在不同运行目录会出错
with open("articles.json", "r") as f:
data = json.load(f)
# ✅ 正确示例:用绝对路径或确保文件在正确位置
import os
data_file = os.path.join(os.path.dirname(__file__), "articles.json")
with open(data_file, "r", encoding="utf-8") as f:
data = json.load(f)
解释: __file__ 是当前 Python 文件的路径,配合 os.path.dirname 就能找到和数据文件的相对位置。
坑 2:JSON 中文乱码
# ❌ 错误示例:没有指定编码,中文会变成乱码
json.dump(data, f)
# ✅ 正确示例:明确指定 utf-8 编码
json.dump(data, f, ensure_ascii=False, indent=2)
解释: ensure_ascii=False 让中文保持中文,而不是变成 \u4e2d\u6587 这种转义。
坑 3:列表推导式写错条件
# ❌ 错误示例:想筛选点赞>100,但写成了赋值
popular = [a for a in articles if a["likes"] = 100] # 语法错误!
# ✅ 正确示例:用 == 比较,用 > 做判断
popular = [a for a in articles if a["likes"] > 100]
解释: = 是赋值,== 是比较,>/< 也是比较。别搞混!
坑 4:Flask 端口被占用
# ❌ 错误示例:端口被其他程序占用会报错
app.run(port=5000)
# ✅ 正确示例:换一个端口试试
app.run(port=5001) # 或者
app.run(port=5000, debug=True)
调试技巧: 报错信息里会写 Port 5000 is in use,换个端口就行。
性能小贴士:避免重复读文件
# ❌ 低效示例:每次请求都读文件
@app.route("/api/articles")
def get_articles():
with open("articles.json", "r") as f:
return jsonify(json.load(f))
# ✅ 高效示例:程序启动时读一次,数据放内存
articles = []
def load_once():
global articles
with open("articles.json", "r") as f:
articles = json.load(f)
@app.route("/api/articles")
def get_articles():
return jsonify(articles)
解释: 磁盘 IO 比内存访问慢几十倍,高频读取的场景要把数据放内存里。
调试技巧:print 大法
def buggy_function(data):
print(f"DEBUG: 收到的数据是 {data}") # 打印出来看看
# ... 更多代码
print(f"DEBUG: 处理后是 {result}")
return result
解释: 不知道变量里装的啥?print() 一下,比单步调试快多了。Flask 加 debug=True 后,网页报错也能看到详细信息。
✏️ 练习题 + 作业题
练习 1(1 分钟):改个变量
# 输入:在项目 1 基础上,把打印格式里的 "❤️" 改成 "👍"
# 预期输出:点赞数后面显示 👍 而不是 ❤️
提示: 搜索代码里的 "❤️",替换成 "👍"。
练习 2(2 分钟):加一个判断
# 输入:在项目 1 里,如果文章点赞数超过 150,在标题后面加个 "🔥" 标记
# 预期输出:Redis缓存实战🔥 (点赞: 200)
提示: 用 if a["likes"] > 150 判断,满足条件就拼接 "🔥"。
练习 3(3 分钟):处理新数据
# 输入:用项目 2 的方法,创建一个 "comments.json" 文件,
# 包含评论数据(id, article_id, user, content),
# 然后筛选指定 article_id 的评论
提示: 数据结构和 articles.json 类似,只是字段不同。
练习 4(4 分钟):串两个项目
# 输入:把项目 2 的筛选功能,加入项目 3 的菜单系统
# 预期输出:选择"筛选"后,输入作者名,能看到筛选结果
提示: 把项目 2 的筛选逻辑封装成函数,在 main() 的 while 循环里调用。
练习 5(挑战题,5 分钟):报错分析
# 以下代码运行报错:KeyError: 'title'
# 请分析原因并修复
articles = [{"id": 1, "name": "Python入门"}]
print(articles[0]["title"])
提示: 字典里的 key 是 name 不是 title,字段名要对应上。
作业:做一个「博客评论统计工具」
需求描述: 做一个命令行小工具,统计文章的评论数据。
功能点:
1. 读取评论数据(comments.json,包含 article_id, user, content, created_at)
2. 按文章 ID 统计每篇文章的评论数
3. 找出评论最多的文章
4. 支持导出统计结果到 CSV 文件
加分项:
1. 支持按日期筛选某天的评论
2. 统计每个用户的评论数量
验收标准:
- 能跑起来(python main.py)
- 输入 1/2/3 等选项有对应输出
- 导出的 CSV 文件能用 Excel 打开
提交方式: 评论区贴代码或 GitHub 链接。
📚 总结 + 资源
本文学到的 3 个核心点:
- JSON 是数据的"万能钥匙"——读写 JSON 就等于和外部数据打交道
- 列表推导式是数据过滤的流水线——一行代码搞定筛选和转换
- Flask 是快速搭 API 的神器——5 行代码就能本地跑一个接口
延伸学习资源:
- Flask 官方文档——最权威的参考手册
- 《Python 编程:从入门到实践》——项目驱动,适合练手
- Real Python——大量实战教程,英文为主
互动钩子: 你有没有遇到过"明明代码没错,但就是跑不起来"的玄学情况?评论区聊聊你是怎么解决的,老粉优先回复!
下章预告: PHP 从入门到精通系列到这里就全部结束了。回顾一下,我们从变量、循环学起,一路走到了能独立做项目的程度。但这不意味着学习终点——真正的高手不是靠背语法,而是靠项目喂出来的。建议你可以:找一个小问题(比如"我想爬取某网站的文章标题"),用学到的知识试着解决它。遇到不会的,再去查文档。做中学,才是编程最快的路。 🎉

评论(0)