Python 实战项目
学了 17 篇基础,是时候把它们串起来做点真东西了。这一章给三个完整、可运行的项目——网页爬虫、数据分析、命令行工具,每个都从需求出发,给出完整代码、运行结果和要点讲解。三个项目覆盖了 Python 最常见的三个应用方向:网络采集、数据处理、自动化脚本。建议你把代码复制到本地亲手跑一遍,再试着改一改需求,这才是真正"上手"的感觉。
实战 1:网页爬虫(requests + BeautifulSoup)
需求:抓取 quotes.toscrape.com(一个专门给爬虫练习用的网站)首页全部名言和作者,保存到 CSV 文件。
涉及知识:HTTP 请求、HTML 解析(CSS 选择器)、异常处理、礼貌爬取(延迟 + User-Agent)、CSV 写入。先装依赖:pip install requests beautifulsoup4。
# spider.py — 网页爬虫:抓取名言网(quotes.toscrape.com)的名言和作者
# 依赖安装:pip install requests beautifulsoup4
import requests
from bs4 import BeautifulSoup
import time
import csv
URL = "https://quotes.toscrape.com/"
HEADERS = {"User-Agent": "Mozilla/5.0 (compatible; MyBot/1.0)"}
DELAY = 1 # 每次请求间隔 1 秒,做个礼貌的爬虫
def fetch(url):
"""发起 HTTP 请求,返回 BeautifulSoup 对象;失败返回 None"""
try:
resp = requests.get(url, headers=HEADERS, timeout=10)
resp.raise_for_status() # 4xx / 5xx 会抛 HTTPError
return BeautifulSoup(resp.text, "html.parser")
except requests.RequestException as e:
print(f"[错误] 请求失败: {e}")
return None
def parse(soup):
"""从 HTML 中提取感兴趣的数据(CSS 选择器定位)"""
items = []
for q in soup.select(".quote"):
text = q.select_one(".text").get_text(strip=True)
author = q.select_one(".author").get_text(strip=True)
items.append({"text": text, "author": author})
return items
def save(items, path="quotes.csv"):
"""把结果写入 CSV 文件"""
with open(path, "w", newline="", encoding="utf-8") as f:
writer = csv.DictWriter(f, fieldnames=["text", "author"])
writer.writeheader()
writer.writerows(items)
print(f"[完成] 已保存 {len(items)} 条到 {path}")
def main():
print(f"[开始] 爬取 {URL}")
time.sleep(DELAY) # 礼貌延迟,别给服务器压力
soup = fetch(URL)
if not soup:
return
items = parse(soup)
print(f"[预览] 共 {len(items)} 条,前 3 条:")
for it in items[:3]:
print(f" - {it['author']}: {it['text'][:40]}")
save(items)
if __name__ == "__main__":
main()
# 输出:
# [开始] 爬取 https://quotes.toscrape.com/
# [预览] 共 10 条,前 3 条:
# - Albert Einstein: The world as we have created it is a proc
# - J.K. Rowling: It is our choices, Harry, that show what we
# - Albert Einstein: There are only two ways to live your life
# [完成] 已保存 10 条到 quotes.csv要点讲解:
requests.get:发 HTTP GET 请求;headers带 User-Agent 是为了让网站识别"我是谁",有些站会拒绝默认 UA。raise_for_status:状态码不是 2xx 就主动抛异常,比"静默失败"健康得多。try / except:网络不可控(超时、断网、404、500),必须包起来;捕获基类RequestException一网打尽所有 requests 异常。BeautifulSoup:把 HTML 字符串解析成可查询的树;select用 CSS 选择器定位元素,get_text(strip=True)取干净文本。- 礼貌爬取:
time.sleep(DELAY)在请求间留间隔,不对服务器施压;这是爬虫的基本礼仪,也是反爬封 IP 的最简单预防。 - 关注 robots.txt:正式爬取前应看目标站点的
robots.txt,尊重站方的爬取规则。
实战 2:销售数据分析(pandas)
需求:给定一份销售流水(日期 / 商品 / 数量 / 单元),算出每种商品的总销量、总销售额,找出销售额 Top 3,把汇总结果导出成新 CSV。
涉及知识:DataFrame 构建 / 读取、列运算、统计描述、布尔筛选、排序、分组聚合 groupby、CSV 导出。先装依赖:pip install pandas。
# analysis.py — 销售数据分析:读 CSV → 统计 → 筛选排序 → 分组聚合 → 导出
# 依赖安装:pip install pandas
import pandas as pd
# 1. 准备数据(实际项目用 df = pd.read_csv("sales.csv"))
data = {
"日期": ["2024-01-01", "2024-01-01", "2024-01-02", "2024-01-02", "2024-01-03",
"2024-01-03", "2024-01-03", "2024-01-04", "2024-01-04", "2024-01-05"],
"商品": ["苹果", "香蕉", "苹果", "橙子", "香蕉",
"苹果", "橙子", "香蕉", "苹果", "橙子"],
"数量": [10, 8, 15, 6, 12, 20, 9, 14, 18, 7],
"单价": [5.0, 3.0, 5.0, 4.0, 3.0, 5.0, 4.0, 3.0, 5.0, 4.0],
}
df = pd.DataFrame(data)
df["金额"] = df["数量"] * df["单价"] # 新增一列:销售额
print("=== 原始数据(前 5 行)===")
print(df.head())
# 输出:
# 日期 商品 数量 单价 金额
# 0 2024-01-01 苹果 10 5.0 50.0
# 1 2024-01-01 香蕉 8 3.0 24.0
# 2 2024-01-02 苹果 15 5.0 75.0
# 3 2024-01-02 橙子 6 4.0 24.0
# 4 2024-01-03 香蕉 12 3.0 36.0
# 2. 统计描述:一眼看分布(均值、最大最小、标准差)
print("\n=== 数值列统计描述 ===")
print(df[["数量", "金额"]].describe())
# 输出:
# 数量 金额
# count 10.00000 10.000000
# mean 11.90000 55.300000
# std 4.72464 22.541535
# min 6.00000 24.000000
# 25% 8.75000 36.000000
# 50% 11.50000 50.000000
# 75% 15.50000 75.000000
# max 20.00000 90.000000
# 3. 筛选:金额大于 50 的订单
big = df[df["金额"] > 50]
print("\n=== 金额 > 50 的订单 ===")
print(big[["日期", "商品", "金额"]])
# 输出:
# 日期 商品 金额
# 2 2024-01-02 苹果 75.0
# 5 2024-01-03 苹果 100.0
# 8 2024-01-04 苹果 90.0
# 4. 排序:按金额降序,取 Top 3
top3 = df.sort_values("金额", ascending=False).head(3)
print("\n=== 销售额 Top 3 ===")
print(top3[["商品", "数量", "金额"]])
# 输出:
# 商品 数量 金额
# 5 苹果 20 100.0
# 8 苹果 18 90.0
# 2 苹果 15 75.0
# 5. 分组聚合:按商品统计总销量、总销售额、订单数
summary = df.groupby("商品").agg(
总数量=("数量", "sum"),
总销售额=("金额", "sum"),
订单数=("金额", "count"),
).reset_index()
print("\n=== 按商品汇总 ===")
print(summary)
# 输出:
# 商品 总数量 总销售额 订单数
# 0 橙子 22 88.0 3
# 1 苹果 63 315.0 4
# 2 香蕉 34 102.0 3
# 6. 导出结果到 CSV(utf-8-sig 让 Excel 打开不乱码)
summary.to_csv("sales_summary.csv", index=False, encoding="utf-8-sig")
print("\n已导出到 sales_summary.csv")
# 输出:
# 已导出到 sales_summary.csv要点讲解:
pd.read_csv:实际项目里用这个读文件;这里为了能直接跑用pd.DataFrame(data)内联造数据。- 列运算:
df["金额"] = df["数量"] * df["单价"]是矢量化的,对整列同时运算,不用写循环——这是 pandas 的核心思维。 describe():一行看分布(均值 / 标准差 / 最小最大 / 分位数),数据探索第一步。- 布尔筛选:
df[df["金额"] > 50]拿出满足条件的行,类似 SQL 的WHERE。 sort_values:排序;ascending=False降序,配合head(3)就是 Top 3。groupby + agg:分组聚合是 pandas 的灵魂,等价于 SQL 的GROUP BY。命名聚合总数量=("数量", "sum")让输出列名清晰。to_csv:导出;用utf-8-sig编码是为了让 Excel 双击打开不乱码(纯utf-8在 Excel 里中文会乱)。
实战 3:命令行工具 todo(argparse)
需求:做一个待办管理 CLI,支持三个子命令——add 添加、list 列出、done 标记完成,数据存 JSON 文件。能脱离 Python 解释器,像真实工具那样在终端用。
涉及知识:标准库 argparse(子命令、参数解析、自动帮助)、JSON 读写、文件路径、datetime 格式化。无需第三方依赖。
# todo.py — 简易待办管理 CLI(支持 add / list / done 三个子命令)
# 无需第三方依赖,纯标准库
import argparse
import json
import os
from datetime import datetime
TODO_FILE = "todos.json"
def load_todos():
"""从文件读取待办列表;文件不存在返回空列表"""
if os.path.exists(TODO_FILE):
with open(TODO_FILE, "r", encoding="utf-8") as f:
return json.load(f)
return []
def save_todos(todos):
"""保存待办列表到文件"""
with open(TODO_FILE, "w", encoding="utf-8") as f:
json.dump(todos, f, ensure_ascii=False, indent=2)
def cmd_add(args):
todos = load_todos()
todo = {
"id": len(todos) + 1,
"title": args.title,
"done": False,
"created": datetime.now().strftime("%Y-%m-%d %H:%M"),
}
todos.append(todo)
save_todos(todos)
print(f"已添加: [{todo['id']}] {todo['title']}")
def fmt(t):
"""格式化一条待办为字符串"""
mark = "x" if t["done"] else " "
return f"[{mark}] {t['id']}. {t['title']} ({t['created']})"
def cmd_list(args):
todos = load_todos()
items = todos if args.all else [t for t in todos if not t["done"]]
if not items:
print("(空空如也)")
return
for t in items:
print(fmt(t))
def cmd_done(args):
todos = load_todos()
for t in todos:
if t["id"] == args.id:
t["done"] = True
save_todos(todos)
print(f"已完成: {t['title']}")
return
print(f"未找到 id={args.id} 的待办")
def main():
parser = argparse.ArgumentParser(
description="简易待办管理 CLI",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="示例:\n"
" python todo.py add 买牛奶\n"
" python todo.py list\n"
" python todo.py list --all\n"
" python todo.py done 1\n",
)
sub = parser.add_subparsers(dest="command", required=True, help="子命令")
p_add = sub.add_parser("add", help="添加一条待办")
p_add.add_argument("title", help="待办内容")
p_list = sub.add_parser("list", help="列出未完成待办")
p_list.add_argument("--all", action="store_true", help="显示全部(含已完成)")
p_done = sub.add_parser("done", help="标记某条为已完成")
p_done.add_argument("id", type=int, help="待办 id")
args = parser.parse_args()
if args.command == "add":
cmd_add(args)
elif args.command == "list":
cmd_list(args)
elif args.command == "done":
cmd_done(args)
if __name__ == "__main__":
main()
# === 用法示例(在终端依次运行)===
# $ python todo.py add 买牛奶
# 已添加: [1] 买牛奶
# $ python todo.py add 写季度报告
# 已添加: [2] 写季度报告
# $ python todo.py list
# [ ] 1. 买牛奶 (2024-06-01 10:30)
# [ ] 2. 写季度报告 (2024-06-01 10:31)
# $ python todo.py done 1
# 已完成: 买牛奶
# $ python todo.py list
# [ ] 2. 写季度报告 (2024-06-01 10:31)
# $ python todo.py list --all
# [x] 1. 买牛奶 (2024-06-01 10:30)
# [ ] 2. 写季度报告 (2024-06-01 10:31)
# $ python todo.py -h
# usage: todo.py [-h] {add,list,done} ...
# 简易待办管理 CLI要点讲解:
add_subparsers:子命令模式(git add/git commit就是这种),每个子命令有自己的参数和帮助,是写复杂 CLI 的标准姿势。- 位置参数 vs 可选参数:
add_argument("title")是位置参数(必填),add_argument("--all", action="store_true")是开关标志(带则 True)。 - 自动帮助:
-h / --help是 argparse 自动生成的,子命令也各自有帮助;写好help=文档很重要。 - JSON 持久化:用
json.load / json.dump把待办存成 JSON;ensure_ascii=False让中文不被转成\uXXXX。 if __name__ == "__main__":Python 的入口惯例——只有直接运行此文件才执行main(),被import时不执行,方便别的模块复用函数。- 可扩展方向:加
delete/edit子命令、按关键词过滤、加优先级、改用 SQLite 存储——每个方向都是练手好题目。
小结
三个项目分别对应 Python 三大主力场景:爬虫(采集数据)、数据分析(理解数据)、CLI 工具(自动化日常)。它们都用到了前面学的基础——函数、字典、文件读写、异常处理、模块——只是组合起来解决真实问题。建议你至少把其中一个改造成自己的版本(换爬取目标、换数据集、给 todo 加新子命令),做过一遍比读十遍更扎实。
恭喜!到这里 Python 系列就真正完结了。接下来挑一个方向深入——Web 后端(Django / FastAPI)、数据分析深入(pandas + 可视化)、AI(llama-index / transformers)、自动化(把日常重复工作交给脚本)——边做边学,进步最快。
← 上一篇 Python 日期时间
返回 Python 教程目录