Python能做什么项目?从爬虫到Web应用,从数据分析到自动化办公,Python几乎无所不能。这篇文章整理了9个有趣又实用的小项目,每个都配有完整的项目结构和代码讲解,适合毕业设计或者自学练手。
完整源码链接:
https://pan.quark.cn/s/1e54aa2ae950项目列表
- 项目2:豆瓣电影Top250爬虫
- 项目3:Flask个人日记本
- 项目4:命令行天气查询工具
- 项目5:Excel自动化报表生成
- 项目6:图片批量压缩水印工具
- 项目7:简易数据分析可视化(房价分析)
- 项目8:定时发送邮件提醒
- 项目9:命令行待办事项清单
- 项目10:QR码生成器解码器
日记本项目
项目2:豆瓣电影Top250爬虫
豆瓣电影Top250爬虫是一个非常经典的Python入门项目,它几乎涵盖了爬虫开发的所有核心知识点。通过这个项目,你可以学会怎么用Python从网页上抓取数据、怎么解析HTML、怎么把数据保存到本地文件,还能做简单的数据分析。
项目结构
这个项目的目录组织体现了从单脚本到多模块的演进思路:
项目2_豆瓣电影Top250爬虫/ ├── main.py # 主入口 ├── crawler.py # 爬虫核心逻辑 ├── data_saver.py # 数据存储模块 ├── analysis.py # 数据分析模块 ├── data.csv # CSV格式数据 ├── data.json # JSON格式数据 └── requirements.txt # 依赖库main.py是启动文件,crawler.py负责爬取,data_saver.py负责保存,analysis.py负责数据分析。这种分模块设计的好处是职责清晰,后期想换数据存储方式或者加新的分析功能,只需要改对应的模块。
爬虫核心代码
爬虫的第一步是准备请求头。豆瓣对爬虫比较敏感,所以要把User-Agent设置成浏览器的样子,模拟真实用户访问。
import requests from bs4 import BeautifulSoup import csv import os import time import random HEADERS = { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36' }然后是带重试机制的请求函数。网络请求经常会因为各种原因失败,加上重试机制可以让爬虫更稳定。这里用了指数退避策略,第一次失败等2秒,第二次等4秒,第三次等6秒。
def fetch_page(url, params=None, retries=3): for attempt in range(retries): try: resp = requests.get(url, params=params, headers=HEADERS, timeout=10) resp.raise_for_status() return resp.text except requests.exceptions.RequestException as e: wait = (attempt + 1) * 2 print(f'请求失败(第{attempt+1}次): {e},{wait}秒后重试...') time.sleep(wait) return None解析电影信息时,除了提取电影名和评分,还增加了导演、年份、国家、经典台词、评价人数等字段。
def parse_movie_item(item): title_tag = item.find('span', class_='title') title = title_tag.text if title_tag else '未知' rating_tag = item.find('span', class_='rating_num') rating = rating_tag.text if rating_tag else '0.0' quote_tag = item.find('span', class_='inq') quote = quote_tag.text if quote_tag else '' bd_tag = item.find('p', class_='') # 提取导演、年份、国家等更多信息... return { 'title': title, 'rating': float(rating), 'quote': quote, 'year': year, 'country': country, 'director': director }豆瓣Top250一共有10页,每页25部电影。通过循环依次请求每一页,每爬完一页休息1-2秒,防止被封。
def crawl_top250(): all_movies = [] for page in range(10): url = 'https://movie.douban.com/top250' params = {'start': page * 25, 'filter': ''} html = fetch_page(url, params) if not html: continue soup = BeautifulSoup(html, 'html.parser') items = soup.find_all('div', class_='item') for item in items: movie = parse_movie_item(item) all_movies.append(movie) print(f'第{page+1}页完成,已累计获取{len(all_movies)}条') time.sleep(random.uniform(1, 2)) return all_movies数据存储
数据同时保存为CSV和JSON两种格式。CSV适合用Excel打开查看,JSON适合程序读取。
def save_to_csv(movies, filename='data.csv'): path = os.path.join(BASE_DIR, filename) with open(path, 'w', newline='', encoding='utf-8-sig') as f: writer = csv.writer(f) writer.writerow(['排名', '电影名', '导演', '年份', '国家', '评分', '评价人数', '经典台词']) for i, m in enumerate(movies, 1): writer.writerow([i, m['title'], m['director'], m['year'], m['country'], m['rating'], m['rating_people'], m['quote']])保存路径使用os.path.dirname(os.path.abspath(file))获取当前脚本所在目录,这是Python项目获取根目录的经典方法。
数据分析
爬取完数据后可以对数据做多维度的统计分析。
def analyze_ratings(movies): ratings = [m['rating'] for m in movies] print(f'平均评分: {sum(ratings)/len(ratings):.2f}') print(f'9.5分以上: {len([m for m in movies if m["rating"] >= 9.5])}部') def analyze_country(movies): country_count = {} for m in movies: c = m.get('country', '未知') country_count[c] = country_count.get(c, 0) + 1 def analyze_year(movies): # 按年代统计:1990年代、2000年代... for decade, count in sorted_years: bar = '█' * (count // 2) print(f'{decade}年代: {count}部 {bar}')运行效果
执行python main.py后,控制台逐页显示爬取进度:
开始爬取豆瓣电影Top250... 第1页完成,已累计获取25条 ... 第10页完成,已累计获取250条 ===== 评分分析 ===== 平均评分: 9.23 9.5分以上: 3部 9.0-9.4分: 22部 ===== 国家/地区分布 ===== 美国: 128部 日本: 45部 中国: 30部data.csv中的数据(前5条):
| 排名 | 电影名 | 导演 | 年份 | 评分 | 经典台词 |
|---|---|---|---|---|---|
| 1 | 肖申克的救赎 | 弗兰克·德拉邦特 | 1994 | 9.7 | 希望是美好的 |
| 2 | 霸王别姬 | 陈凯歌 | 1993 | 9.6 | 不疯魔不成活 |
| 3 | 阿甘正传 | 罗伯特·泽米吉斯 | 1994 | 9.5 | 生活就像一盒巧克力 |
| 4 | 泰坦尼克号 | 詹姆斯·卡梅隆 | 1997 | 9.4 | 赢得船票是我一生最幸运的事 |
| 5 | 这个杀手不太冷 | 吕克·贝松 | 1994 | 9.4 | 人生总是这么痛苦吗 |
要点总结
一个完整的爬虫项目分为四个步骤:请求网页、解析数据、保存结果、分析数据。多模块组织让代码更清晰,重试机制让爬虫更稳定。项目根目录用os.path.dirname(os.path.abspath(file))获取是通用做法。
扩展思路:加代理IP池防止被封;结合可视化库把评分分布画成图表;改成爬其他网站(知乎热榜、B站排行榜等)。
项目3:Flask个人日记本
Flask个人日记本是一个真正能用的Web应用,从注册登录到写日记、分类管理、搜索、统计,功能一应俱全。这个项目能让你从零开始学习Web开发的核心概念。
项目结构
项目3_Flask个人日记本/ ├── app.py # Flask应用主程序 ├── init_db.py # 数据库初始化脚本 ├── diary.db # SQLite数据库文件 ├── requirements.txt # 依赖库 ├── templates/ # HTML模板文件夹 │ ├── base.html # 基础模板 │ ├── index.html # 日记列表页 │ ├── edit.html # 新增/编辑日记页 │ ├── login.html # 登录页 │ ├── register.html # 注册页 │ └── stats.html # 统计页 └── static/ # 静态资源文件夹 └── style.css # 样式文件templates使用模板继承,base.html是基础框架,其他页面继承base.html就自动拥有了导航栏和样式。这种设计避免了重复代码,也是大型Web项目的标准做法。
数据库设计
项目使用SQLite数据库,Python内置的sqlite3模块就可以操作。数据库有三张表:users(用户)、categories(分类)、diaries(日记)。
# init_db.py import sqlite3 def init_database(): conn = sqlite3.connect(DB_PATH) c = conn.cursor() c.execute('''CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password TEXT NOT NULL )''') c.execute('''CREATE TABLE IF NOT EXISTS categories ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL )''') c.execute('''CREATE TABLE IF NOT EXISTS diaries ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, category_id INTEGER, title TEXT NOT NULL, content TEXT NOT NULL, created_at TEXT DEFAULT (datetime('now','localtime')), FOREIGN KEY (user_id) REFERENCES users(id) )''') # 预置默认分类 default_categories = ['日常', '工作', '学习', '旅行', '心情', '其他'] for cat in default_categories: c.execute('INSERT INTO categories (name) VALUES (?)', (cat,)) conn.commit() conn.close()用户认证系统
用户密码使用SHA256加密存储,Flask的session维持登录状态,login_required装饰器保护需要登录才能访问的页面。
from functools import wraps def hash_password(password): return hashlib.sha256(password.encode()).hexdigest() def login_required(f): @wraps(f) def decorated_function(*args, **kwargs): if 'user_id' not in session: return redirect(url_for('login')) return f(*args, **kwargs) return decorated_function日记增删改查
日记列表支持按分类筛选和关键词搜索,搜索会同时匹配标题和内容。
@app.route('/') @login_required def index(): db = get_db() category = request.args.get('category') search = request.args.get('search') query = 'SELECT d.*, c.name as category_name FROM diaries d LEFT JOIN categories c ON d.category_id = c.id WHERE d.user_id = ?' params = [session['user_id']] if category: query += ' AND d.category_id = ?' params.append(category) if search: query += ' AND (d.title LIKE ? OR d.content LIKE ?)' params.extend([f'%{search}%', f'%{search}%']) query += ' ORDER BY d.created_at DESC' diaries = db.execute(query, params).fetchall() categories = db.execute('SELECT * FROM categories').fetchall() return render_template('index.html', diaries=diaries, categories=categories)新增和编辑共用一个模板,通过mode参数区分模式。
@app.route('/add', methods=['GET', 'POST']) @login_required def add(): if request.method == 'POST': title = request.form['title'] content = request.form['content'] category_id = request.form.get('category_id') db.execute('INSERT INTO diaries (user_id, category_id, title, content) VALUES (?, ?, ?, ?)', (session['user_id'], category_id, title, content)) db.commit() return redirect(url_for('index')) return render_template('edit.html', diary=None, categories=categories, mode='add')运行效果
运行python app.py启动服务,访问http://127.0.0.1:5000:
- 首次使用先注册账号
- 登录后进入日记列表页,看到所有日记按时间倒序排列
- 点击"写新日记"输入标题和内容,选择分类后发布
- 日记列表支持按分类筛选和关键词搜索
- 每篇日记可以编辑或删除
- 统计页面展示总日记数和各分类的数量及占比
页面使用了Bootstrap框架,在不同屏幕尺寸下都能正常显示。
要点总结
Flask开发Web应用的核心就是路由、模板、数据库三者配合。SQLite适合小型应用,模板继承避免重复代码,装饰器实现登录校验很优雅。项目根目录用app.root_path获取,这是Flask内置的功能。
扩展思路:加Markdown编辑器支持富文本;添加图片上传功能;部署到服务器上真正用起来。
项目4:命令行天气查询工具
在终端里输入城市名就能看到实时天气,还支持未来多日预报和查询历史记录。这个项目主要锻炼三个技能:调用外部API、用argparse构建命令行工具、模块化组织代码。
项目结构
项目4_命令行天气查询工具/ ├── main.py # 主入口 ├── weather_api.py # API请求封装 ├── formatter.py # 输出格式化(含颜色) ├── history.py # 查询历史记录 ├── history.db # SQLite历史数据库 └── requirements.txt # 依赖库API调用
使用wttr.in这个公共天气API,不需要注册也不需要API Key。format=j1返回JSON,lang=zh用中文显示。
def fetch_weather(city, days=1): url = f'https://wttr.in/{city}?format=j1&lang=zh' if days > 1: url = f'https://wttr.in/{city}?format=j1&lang=zh&days={days}' resp = requests.get(url, timeout=10) resp.raise_for_status() return resp.json()返回的JSON用parse_current和parse_forecast两个函数分别提取实时数据和预报数据。
def parse_current(data): current = data['current_condition'][0] return { 'weather': current['lang_zh'][0]['value'], 'temp': current['temp_C'], 'feels_like': current['FeelsLikeC'], 'humidity': current['humidity'], 'wind_speed': current['windspeedKmph'], 'wind_dir': current['winddir16Point'], 'pressure': current['pressure'], 'visibility': current['visibility'], 'uv_index': current['uvIndex'], }彩色终端输出
使用colorama库让输出带上颜色。温度用红色,天气状况用黄色,城市名用绿色。
def format_weather_detail(current): lines = [] lines.append(f'天气状况: {yellow(current["weather"])}') lines.append(f'当前温度: {red(current["temp"] + "°C")}') lines.append(f'体感温度: {current["feels_like"]}°C') lines.append(f'湿度: {current["humidity"]}%') lines.append(f'风速: {current["wind_speed"]} km/h ({current["wind_dir"]})') return '\n'.join(lines)查询历史
每次查询自动保存到SQLite数据库,通过–history参数查看记录。
def save_query(city, temp='', weather=''): conn.execute('INSERT INTO queries (city, temp, weather) VALUES (?, ?, ?)', (city, temp, weather))运行效果
实时天气查询:
python main.py 成都 ====== 成都 天气 ====== 天气状况: 多云 当前温度: 28°C 体感温度: 30°C 湿度: 65% 风速: 12 km/h (南)未来3天预报:
python main.py 北京 --days 3 ====== 北京 未来3天预报 ====== 7月28日 多云 24°C ~ 35°C 7月29日 晴 26°C ~ 37°C 7月30日 阴转小雨 22°C ~ 31°C查看历史:
python main.py --history 最近的5次查询记录: 2026-07-28 14:30 | 成都 | 28°C | 多云要点总结
API调用的核心是requests库的get方法,关键在于理解返回的数据结构。argparse让Python脚本有了专业的命令行界面。colorama给终端输出增加颜色。
扩展思路:接入和风天气等更专业的API;加天气预警功能,极端天气时自动通知。
项目5:Excel自动化报表生成
用Python自动生成Excel报表,可以把几小时的手工操作缩短到几秒钟。这个项目演示了如何用openpyxl库创建专业的Excel报表,包含数据汇总、图表生成、多工作表管理。
项目结构
项目5_Excel自动化报表生成/ ├── generate_report.py # 报表生成主程序 ├── sample_data.xlsx # 示例源数据 ├── 销售报表.xlsx # 生成的完整报表 └── requirements.txt # 依赖库生成的销售报表包含三个工作表:销售汇总(含柱状图和饼图)、产品销售明细、数据看板。
数据准备
项目内置15条销售数据,涵盖数码、服装、家居三个品类。
| 日期 | 产品 | 品类 | 销量 | 单价 | 销售额 |
|---|---|---|---|---|---|
| 2025-01-05 | 笔记本电脑 | 数码 | 15 | 4999 | 74985 |
| 2025-01-08 | 机械键盘 | 数码 | 30 | 399 | 11970 |
| 2025-01-12 | 羽绒服 | 服装 | 20 | 599 | 11980 |
样式系统
定义了统一的样式字典,所有工作表共用一套样式标准。
STYLE = { 'header_fill': PatternFill(start_color='2F5496', end_color='2F5496', fill_type='solid'), 'header_font': Font(name='SimHei', bold=True, color='FFFFFF'), 'title_font': Font(name='SimHei', bold=True, size=16, color='2F5496'), 'thin_border': Border( left=Side(style='thin', color='B4B4B4'), right=Side(style='thin', color='B4B4B4'), top=Side(style='thin', color='B4B4B4'), bottom=Side(style='thin', color='B4B4B4') ), 'center': Alignment(horizontal='center', vertical='center'), 'money_format': '#,##0', }销售汇总表
按品类分组计算总销量、总销售额、平均单价等,底部显示合计行。
def create_summary_sheet(wb, data): category_data = {} for row in data: cat = row[2] if cat not in category_data: category_data[cat] = {'qty': 0, 'amount': 0, 'count': 0} category_data[cat]['qty'] += row[3] category_data[cat]['amount'] += row[5] category_data[cat]['count'] += 1 # 写入汇总数据...同时插入柱状图和饼图,视觉化展示各品类情况。
chart = BarChart() chart.title = '各品类销售额对比' data_ref = Reference(ws, min_col=3, min_row=4, max_row=row_num - 1) chart.add_data(data_ref, titles_from_data=True) chart.set_categories(cats_ref) ws.add_chart(chart, 'A' + str(row_num + 2)) pie = PieChart() pie.title = '销售额占比分析' ws.add_chart(pie, 'F' + str(row_num + 2))运行效果
完整报表已生成: ...\销售报表.xlsx 包含 3 个工作表: 销售汇总, 产品销售明细, 数据看板汇总数据:
| 品类 | 总销量 | 总销售额 | 平均单价 | 订单数 | 占比 |
|---|---|---|---|---|---|
| 家居 | 143 | 12,417 | 86.83 | 4 | 6.7% |
| 数码 | 140 | 133,910 | 956.50 | 5 | 72.7% |
| 服装 | 215 | 37,935 | 176.44 | 6 | 20.6% |
要点总结
Path(file).parent是处理项目文件路径的推荐方式。openpyxl的样式系统虽然代码多,但能做出很专业的报表。图表支持柱状图、折线图、饼图。
扩展思路:加定时自动生成功能;结合邮件模块自动发送;改成读取数据库生成报表。
项目6:图片批量压缩水印工具
当你有几百张图片需要压缩或加水印时,手动一张张处理效率极低。用Pillow库几行代码就能搞定批量处理。这个工具支持压缩、缩放、水印、格式转换、滤镜等多种功能。
项目结构
项目6_图片批量压缩水印工具/ ├── image_tool.py # 主程序 ├── input/ # 原始图片目录 ├── output/ # 处理后图片目录 └── requirements.txt # 依赖库input放原始图片,output放处理结果。输入输出分离是批量处理任务的标准模式。
批量压缩
压缩的核心是save方法的quality参数,optimize=True启用优化。
def compress(quality=60): for img_path in get_images(): img = Image.open(img_path) out_path = OUTPUT_DIR / f'compressed_{img_path.name}' img.save(out_path, quality=quality, optimize=True)批量调整尺寸
支持指定宽度/高度或缩放比例,使用LANCZOS高质量缩放算法。
def resize(width=None, height=None, ratio=None): if ratio: new_w, new_h = int(w * ratio), int(h * ratio) else: img.thumbnail((rw, rh), Image.LANCZOS) new_w, new_h = img.size添加水印
支持五种位置:左上、右上、左下、右下、居中。透明度可调节。
def add_watermark(text='Python', position='br', opacity=128): font = ImageFont.truetype('C:/Windows/Fonts/simhei.ttf', font_size) positions = {'tl': (0.05, 0.05), 'tr': (0.75, 0.05), 'bl': (0.05, 0.85), 'br': (0.75, 0.85), 'center': (0.35, 0.45)} draw.text((x, y), text, fill=(255, 255, 255, opacity), font=font)格式转换和滤镜
支持jpg/png/bmp/webp互转,滤镜支持模糊、浮雕、锐化、边缘检测等。
运行效果
python image_tool.py compress --quality 50 === 批量压缩 (quality=50) === 示例图片1.jpg: 17.6KB -> 5.2KB (-70%) python image_tool.py watermark --text "我的水印" --pos br === 批量添加水印 (pos=br) === 水印已添加: wm_示例图片1.jpg要点总结
Pillow的Image.open和Image.save是图像处理的基本操作。输入/输出文件夹分离是标准设计。simhei字体在Windows系统里可直接调用。
扩展思路:加图形界面;生成网站缩略图;集成到Flask做在线处理服务。
项目7:简易数据分析可视化(房价分析)
房价分析是数据分析里最贴近生活的案例。用pandas处理数据、matplotlib画图,分析成都五个区域2020年到2024年的房价变化趋势,最终生成完整的HTML分析报告。
项目结构
项目7_简易数据分析可视化(房价分析)/ ├── analysis.py # 分析主程序 ├── data/ # 数据文件夹 │ └── housing_data.csv # 25条房价样本数据 ├── output/ # 输出文件夹 │ ├── 房价走势图.png │ ├── 区域房价对比图.png │ ├── 分布分析图.png │ ├── 各区域走势对比图.png │ ├── 相关性热力图.png │ └── 房价分析报告.html └── requirements.txt # 依赖库数据说明
housing_data.csv包含25条模拟数据,覆盖锦江区、武侯区、高新区、天府新区、成华区五个区域。
| 年份 | 区域 | 小区名 | 单价(元/平) | 面积(平) | 总价(万) |
|---|---|---|---|---|---|
| 2020 | 锦江区 | 绿地锦天府 | 28500 | 120 | 342 |
| 2024 | 高新区 | 金融城8号 | 48000 | 140 | 672 |
数据加载与基本统计
import pandas as pd import matplotlib.pyplot as plt from pathlib import Path plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False def load_data(): df = pd.read_csv(DATA_PATH, encoding='utf-8') return df def basic_statistics(df): numeric_cols = ['单价(元/平)', '面积(平)', '总价(万)'] stats = df[numeric_cols].describe().round(2) print(stats)各区域分析
按区域分组统计,计算均价、最高价、最低价、价格波动情况。
def analyze_by_area(df): grouped = df.groupby('区域').agg({ '单价(元/平)': ['mean', 'min', 'max', 'std'], '总价(万)': ['sum', 'mean'], '面积(平)': 'mean' }).round(2)可视化图表
共生成5张专业图表:
- 房价走势图- 折线图展示五年均价变化
- 区域房价对比图- 横向柱状图
- 分布分析图- 箱线图+散点图组合
- 各区域走势对比图- 五条折线对比
- 相关性热力图- 单价、面积、总价的相关关系
def plot_price_trend(df): yearly = df.groupby('年份')['单价(元/平)'].mean() plt.plot(yearly.index, yearly.values, marker='o', linewidth=2.5, color='#3498db') plt.fill_between(yearly.index, yearly.values, alpha=0.15, color='#3498db') plt.savefig(OUTPUT_DIR / '房价走势图.png', dpi=150, bbox_inches='tight')相关性分析
def correlation_analysis(df): numeric_df = df[['单价(元/平)', '面积(平)', '总价(万)']] corr = numeric_df.corr() # 绘制热力图 plt.matshow(corr, cmap='RdBu_r', vmin=-1, vmax=1)结果显示:单价与总价强正相关(0.951),面积与总价中正相关(0.727)。
HTML分析报告
所有分析结果和图表自动整合成一份HTML报告,在浏览器中直接打开查看。
运行效果
===== 各区域房价统计 ===== 高新区 40000元/平 锦江区 37100元/平 天府新区 30000元/平 武侯区 26800元/平 成华区 23100元/平 ===== 年度趋势 ===== 2020: 25600元/平 2021: 27900元/平 2022: 31600元/平 2023: 34700元/平 2024: 37200元/平(涨幅约45%) ===== 相关性分析 ===== 单价-总价: 0.951 (强相关) 面积-总价: 0.727 (强相关)要点总结
数据分析标准流程:加载→清洗→分析→可视化。pandas的groupby和agg是分组统计核心,matplotlib的subplots支持多图组合。数据路径用Path(file).parent管理。
扩展思路:接入真实房价API;用scikit-learn做价格预测;做成交互式Web应用。
项目8:定时发送邮件提醒
每天早上发送天气预报、定时提醒、定期发送报表——这个项目涉及smtplib发邮件、schedule定时任务、配置分离、日志记录、HTML模板等多个知识点。
项目结构
项目8_定时发送邮件提醒/ ├── main.py # 主程序 ├── config.py # 邮箱配置 ├── email_templates.py # 邮件模板 ├── mail.log # 运行日志 └── requirements.txt # 依赖库配置说明
需要在config.py里填写真实的邮箱信息。QQ邮箱需要开启SMTP服务并生成16位授权码。
SMTP_CONFIG = { 'server': os.getenv('SMTP_SERVER', 'smtp.qq.com'), 'port': int(os.getenv('SMTP_PORT', 587)), 'sender': os.getenv('SMTP_SENDER', 'your_email@qq.com'), 'password': os.getenv('SMTP_PASSWORD', 'your_auth_code'), }发送邮件
smtplib是Python内置库,不需要额外安装。starttls()启动加密传输。
def send_email(subject, body, receiver=None, email_type='plain'): msg = MIMEText(body, 'plain', 'utf-8') msg['From'] = Header(sender) msg['To'] = Header(receiver) msg['Subject'] = Header(subject, 'utf-8') with smtplib.SMTP(server, port) as s: s.starttls() s.login(sender, password) s.sendmail(sender, [receiver], msg.as_string())HTML邮件模板
支持多种模板:通用HTML模板、天气日报模板、待办提醒模板。
def weather_template(city, temp, weather): return f'''<html><body> <div style="background:linear-gradient(135deg,#667eea,#764ba2);color:white;padding:30px;text-align:center;"> <h1>{city}</h1><p style="font-size:48px;">{temp}°C</p> <p>{weather}</p></div></body></html>'''定时任务
使用schedule库,每天9点自动发送。
schedule.every().day.at('09:00').do(send_daily_reminder) while True: schedule.run_pending() time.sleep(30)日志系统
使用logging模块,同时输出到控制台和文件。
logging.basicConfig( level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s', handlers=[logging.FileHandler('mail.log', encoding='utf-8'), logging.StreamHandler()] )运行效果
1. 发送测试邮件 2. 设置每日定时发送(9:00) 3. 查看运行状态选1立即发送HTML格式测试邮件,选2设置定时任务,选3查看配置和日志。
要点总结
配置分离和日志记录是工程化基础。smtplib内置可用,schedule让定时任务变简单。HTML模板让邮件更美观。
扩展思路:结合天气API自动发送每日天气;结合Excel模块发送报表;做邮件订阅系统。
项目9:命令行待办事项清单
涉及增删改查、数据持久化、命令行交互设计、分层架构。升级版加入了优先级、分类、截止日期、搜索和统计。
项目结构
项目9_命令行待办事项清单/ ├── cli.py # 命令行交互层 ├── logic.py # 业务逻辑层 ├── tasks.json # 数据存储 └── requirements.txt # 依赖库cli.py负责交互,logic.py负责数据处理。分层设计让代码更清晰,换界面不影响业务逻辑。
数据模型
task = { 'id': 1, 'title': '完成毕业设计', 'priority': 'high', # high/medium/low 'category': '学习', # 自定义分类 'due_date': '2026-08-15', # 截止日期 'done': False, 'created_at': '2026-07-28 14:30' }数据存储在tasks.json中,JSON格式方便查看和手动编辑。
业务逻辑
class TaskManager: def __init__(self): self.tasks = self._load() def add(self, title, priority='medium', category='默认', due_date=None): task = { 'id': self._next_id(), 'title': title, 'priority': priority, 'category': category, 'due_date': due_date or '', 'done': False, } self.tasks.append(task) self._save() def list_tasks(self, filter_by=None, category=None, priority=None, sort_by='id'): # 支持多维度筛选和排序 def search(self, keyword): # 按关键词搜索标题和分类 def stats(self): # 统计完成率、分类分布、优先级分布命令行接口
使用argparse的子命令系统,支持add/list/done/delete/search/stats。
p_add = sub.add_parser('add', help='添加任务') p_add.add_argument('title') p_add.add_argument('--priority', choices=['high', 'medium', 'low'], default='medium') p_add.add_argument('--category', default='默认') p_add.add_argument('--due', help='截止日期 (YYYY-MM-DD)') p_list = sub.add_parser('list', help='列出任务') p_list.add_argument('--filter', choices=['all', 'done', 'pending'], default='all') p_list.add_argument('--category') p_list.add_argument('--priority', choices=['high', 'medium', 'low']) p_list.add_argument('--sort', choices=['id', 'priority', 'due_date'], default='id')运行效果
python cli.py add "写Python项目" --priority high --category 学习 --due 2026-08-01 已添加任务 [#2]: 写Python项目 python cli.py list --filter pending --sort priority ID 优先级 分类 状态 截止日期 任务 2 高 学习 待办 2026-08-01 写Python项目 1 低 生活 待办 - 买菜 python cli.py stats ====== 任务统计 ====== 总任务: 12 已完成: 5 (41.7%) 按分类: 学习: 5, 工作: 4, 生活: 1要点总结
分层设计(cli+logic)让代码清晰可扩展。JSON持久化适合小规模数据。argparse支持子命令和参数类型检查。数据文件路径用Path(file).parent确定。
扩展思路:加系统通知提醒功能;云端同步;做Web版。
项目10:QR码生成器解码器
用Python生成和解码二维码,支持普通二维码、带Logo的二维码、WiFi配置二维码、电子名片二维码,还能用摄像头实时扫描。
项目结构
项目10_QR码生成器解码器/ ├── qr_tool.py # 主程序 ├── output/ # 二维码输出目录 └── requirements.txt # 依赖库生成普通二维码
def generate_qr(data, filename='qr.png', fill_color='black', back_color='white', with_logo=False): qr = qrcode.QRCode( version=1, error_correction=qrcode.constants.ERROR_CORRECT_H, box_size=10, border=4, ) qr.add_data(data) qr.make(fit=True) img = qr.make_image(fill_color=fill_color, back_color=back_color) if with_logo: # 在中间添加Logo图案 logo = Image.new('RGB', (logo_size, logo_size), '#3498db') img.paste(logo, ((img.width - logo_size) // 2, (img.height - logo_size) // 2)) path = OUTPUT_DIR / filename img.save(path)error_correction参数设置为H级(最高纠错),允许30%破损,这是加Logo的前提。
生成WiFi二维码
手机扫描后自动连接WiFi。
def generate_wifi_qr(ssid, password, encryption='WPA'): data = f'WIFI:T:{encryption};S:{ssid};P:{password};;' return generate_qr(data, 'wifi_qr.png')生成电子名片
手机扫描后直接保存联系人。
def generate_vcard_qr(name, phone, email=''): data = f'BEGIN:VCARD\nVERSION:3.0\nFN:{name}\nTEL:{phone}\nEMAIL:{email}\nEND:VCARD' return generate_qr(data, 'vcard_qr.png')解码二维码
使用opencv的QRCodeDetector,同时检测和解码。
def decode_qr(image_path): img = cv2.imread(str(path)) detector = cv2.QRCodeDetector() data, bbox, _ = detector.detectAndDecode(img) if data: print(f'解码成功!内容: {data}') # 自动识别类型 if data.startswith('WIFI:'): print('类型: WiFi 配置') elif data.startswith('BEGIN:VCARD'): print('类型: 电子名片')摄像头实时扫描
调用电脑摄像头实时扫描,在屏幕上绘制二维码边框辅助对准。
def decode_from_camera(): cap = cv2.VideoCapture(0) detector = cv2.QRCodeDetector() while True: ret, frame = cap.read() data, bbox, _ = detector.detectAndDecode(frame) if data: print(f'扫描成功!内容: {data}') break if bbox is not None: # 绘制绿色边框 for i in range(len(bbox)): cv2.line(frame, tuple(bbox[i][0]), tuple(bbox[(i+1) % len(bbox)][0]), (0, 255, 0), 3) cv2.imshow('QR Scanner', frame) if cv2.waitKey(1) & 0xFF == 27: break运行效果
生成二维码: python qr_tool.py generate "https://www.python.org" --logo 二维码已生成: output\qr.png 生成WiFi二维码: python qr_tool.py wifi "MyWiFi" "password123" 二维码已生成: output\wifi_qr.png 解码二维码: python qr_tool.py decode output/qr.png 解码成功!内容: https://www.python.org 类型: 网址链接 摄像头扫描: python qr_tool.py scan 扫描成功!内容: https://www.python.org要点总结
qrcode库负责生成,opencv负责解码,Pillow负责美化。ERROR_CORRECT_H是加Logo的关键。opencv的QRCodeDetector能同时检测和解码。
扩展思路:批量生成名片二维码;做网页版在线生成器;做成手机App。
总结
这9个项目从爬虫、Web开发、API调用、办公自动化、图像处理、数据分析、邮件服务、命令行工具到二维码应用,几乎涵盖了Python开发的全部主要方向。每个项目都可以作为毕业设计的基础,加上自己的业务逻辑就能变成完整作品。