第一阶段的最后一学期,小强要从「会写程序」进化到「会做工程」:爬虫让程序自动上网拿数据,数据库让数据安家,GUI 让程序有脸面,调试与规范让代码能被别人读懂。最后的毕业项目,是他自己选题、自己设计、自己交付的第一个完整「作品」——第一阶段就此圆满。
补齐工程能力:爬虫、正则、多线程、GUI、数据库、调试与代码规范,最后完成自主选题的大型毕业项目。
用故事和生活类比打开这学期的大门,先「知其所以然」再学语法。
第一阶段的最后一学期,小强要从「会写程序」进化到「会做工程」:爬虫让程序自动上网拿数据,数据库让数据安家,GUI 让程序有脸面,调试与规范让代码能被别人读懂。最后的毕业项目,是他自己选题、自己设计、自己交付的第一个完整「作品」——第一阶段就此圆满。
按你的清单去书架(网页)取书,礼貌排队不吵不闹(限速)。
自动取数万字文本里一把筛出所有电话号码、邮箱、日期。
模式匹配存取有账本(SQL),查询有索引,百万数据秒回。
持久化不靠猜,靠证据:断点、单步、看现场,锁定真凶。
定位 bug综合项目与阶段毕业 —— 共 12 课时,全部知识点一网打尽。
import requests
from bs4 import BeautifulSoup
headers = {"User-Agent": "Mozilla/5.0"} # 礼貌地报上身份
resp = requests.get(url, headers=headers, timeout=10)
resp.encoding = "utf-8"
soup = BeautifulSoup(resp.text, "html.parser")
for tag in soup.select(".weather"): # CSS 选择器定位
print(tag.get_text(strip=True))晴 26℃ 东南风3级
多云 22℃ 微风import requests, csv, time
headers = {"User-Agent": "Mozilla/5.0"}
rows = []
for page in range(0, 2): # 翻页:start=0,25,50…
url = "https://movie.example/top250"
r = requests.get(url, params={"start": page * 25}, headers=headers, timeout=5)
print(f"第{page+1}页 状态码 {r.status_code},长度 {len(r.text)}")
time.sleep(1) # 礼貌限速,别把服务器打挂
rows.append(["肖申克的救赎", 9.7])
with open("top250.csv", "w", newline="", encoding="utf-8") as f:
csv.writer(f).writerows(rows) # 存成 CSV第1页 状态码 200,长度 48213
第2页 状态码 200,长度 47986
(top250.csv 已保存,可用 Excel 打开)import re
text = "联系我: xiaoqiang@py.com 或 teacher@school.cn"
emails = re.findall(r"[\w.]+@[\w.]+", text)
print("找到邮箱:", emails)
phones = re.findall(r"1\d{10}", "电话13812345678")
print("找到手机:", phones)找到邮箱: ['xiaoqiang@py.com', 'teacher@school.cn']
找到手机: ['13812345678']import threading
def download(name):
print(f"开始下载 {name} ……")
# ……下载代码……
print(f"{name} 完成!")
ts = []
for i in range(3): # 开 3 条线程
t = threading.Thread(target=download, args=(f"图{i}.png",))
t.start(); ts.append(t)
for t in ts: t.join() # 等全部完成开始下载 图0.png ……
开始下载 图1.png ……
开始下载 图2.png ……
(三个下载交替进行,总耗时≈最长的一个)import tkinter as tk
win = tk.Tk()
win.title("我的记事本")
win.geometry("400x300")
txt = tk.Text(win, font=("simhei", 12))
txt.pack(fill="both", expand=True)
btn = tk.Button(win, text="保存",
command=lambda: print("已保存", len(txt.get("1.0", "end")), "字符"))
btn.pack()
# win.mainloop() # 事件循环:程序的心跳
print("窗口、文本框、按钮三件套已就绪")窗口、文本框、按钮三件套已就绪
(点击「保存」→ 已保存 0 字符)import sqlite3
conn = sqlite3.connect("library.db")
cur = conn.cursor()
cur.execute("""CREATE TABLE IF NOT EXISTS book(
id INTEGER PRIMARY KEY,
name TEXT, price REAL)""")
cur.execute("INSERT INTO book(name, price) VALUES(?, ?)", ("Python入门", 59.0))
conn.commit()
for row in cur.execute("SELECT name, price FROM book WHERE price > 50"):
print(row)('Python入门', 59.0)# 方法一:print 大法(快速但不优雅)
# 方法二:breakpoint() 进交互式调试
# n = 下一行 / p 变量 = 打印 / c = 继续跑
# 方法三:单元测试,把 Bug 锁死
def divide(a, b):
return a / b # 藏着 b=0 的雷
import unittest
class TestDivide(unittest.TestCase):
def test_zero(self):
with self.assertRaises(ZeroDivisionError):
divide(1, 0)
print("用例设计:正常值 / 边界值 / 异常值")用例设计:正常值 / 边界值 / 异常值
(跑 unittest 后 ZeroDivisionError 被测试捕获)# PEP8 核心四条,写代码像写字一样工整
import os,sys # ✗ 一行多个 import
import os
import sys # ✓ 每个 import 独立一行
def f( a,b ): # ✗ 括号里贴太紧
x=1 # ✗ 等号两边没空格
return x
def add(a, b): # ✓ 逗号后空格、运算符两侧空格
total = a + b # ✓ snake_case 命名、小写函数名
return total # ✓ 4 空格缩进
print("可读性 > 聪明,代码是写给人看的")可读性 > 聪明,代码是写给人看的
(IDE 装 flake8 / black 可自动检查和格式化)# 一个 12 课时毕业项目的典型拆解:
plan = {
"第1-2课时": "选题 + 需求文档(做什么/给谁用)",
"第3-5课时": "原型开发(先跑通主流程)",
"第6-8课时": "功能迭代 + 互相 Code Review",
"第9-10课时": "测试修 Bug(每人至少提 3 个 issue)",
"第11-12课时": "演示彩排 + 答辩 PPT",
}
tools = "Git 分支开发 / 共享文档 / 每日站会 10 分钟"
for k, v in plan.items():
print(f"{k}:{v}")
print("工具:", tools)第1-2课时:选题 + 需求文档(做什么/给谁用)
第3-5课时:原型开发(先跑通主流程)
第6-8课时:功能迭代 + 互相 Code Review
第9-10课时:测试修 Bug(每人至少提 3 个 issue)
第11-12课时:演示彩排 + 答辩 PPT
工具: Git 分支开发 / 共享文档 / 每日站会 10 分钟每个知识点都要落到能跑、能玩、能演示的作品上。
期末项目是整学期知识点的综合检验场:项目管理、团队协作。学生将独立完成需求拆解 → 功能实现 → 调试打磨 → 上台演示的完整闭环。
| 课次 | 主题 | 趣味项目 | 知识点 |
|---|---|---|---|
| 1 | 网络爬虫入门 | 爬取天气信息 | requests、BeautifulSoup |
| 2 | 爬虫进阶 | 豆瓣电影Top250 | 多页爬取、数据存储 |
| 3 | 正则表达式 | 文本信息提取 | regex语法 |
| 4 | 多线程 | 同时下载多张图片 | threading |
| 5 | GUI编程 | 记事本程序 | tkinter |
| 6 | 数据库入门 | 图书管理系统 | SQLite、SQL基础 |
| 7 | 代码调试技巧 | 找Bug大作战 | 调试器、单元测试 |
| 8 | 代码规范 | 代码审查会 | PEP8、注释规范 |
| 9-12 | 毕业项目开发 | 自主选题大型项目 | 项目管理、团队协作 |
把一学期的知识点串成体系,看清来路与去向。
◀ 上一章:三年级 上学期 · 算法进阶与NOAI初赛备战
下一章 ▶:四年级 上学期 · 机器学习基础
补齐工程能力:爬虫、正则、多线程、GUI、数据库、调试与代码规范,最后完成自主选题的大型毕业项目。
结业时你将带走:3 个可玩游戏作品 + 一套算法思维 + NOAI 初赛参赛能力。
避开高频易错点,再用速查表把语法焊进肌肉记忆。
requests.get(url)
# 403 Forbiddenrequests.get(url,
headers={"User-Agent": "Mozilla/5.0 …"})re.findall(r"<.*>", "<a>x</a><b>y</b>")
# 一口吞下整行re.findall(r"<.*?>", 同上)
# 逐个标签匹配sql = f"SELECT * FROM t WHERE name='{name}'"cur.execute(
"SELECT * FROM t WHERE name=?", (name,))print(a)
print(a)
print(a) # 疯狂插桩breakpoint() # 交互式调试| 功能 | 写法 | 一句话理解 |
|---|---|---|
| 发请求 | requests.get(url, headers=h) | 取回网页/接口内容 |
| 解析网页 | soup.select("div.title") | CSS 选择器定位元素 |
| 正则提取 | re.findall(r"\d{11}", s) | 筛出 11 位手机号 |
| 开线程 | threading.Thread(target=下载, args=(url,)) | 多张图片同时下载 |
| 建表 | cur.execute("CREATE TABLE book …") | 给数据安家 |
| 查询 | SELECT * FROM book WHERE price > 50 | 条件取数 |
| 调试 | breakpoint() / 单步 n / 看 p 变量 | pdb 三板斧 |
| 规范 | PEP8:4空格缩进、蛇形命名、行宽≤79 | 代码像印刷体一样整洁 |
按 A / B / C 三档难度自主选择:保底完成 A 组,学有余力挑战 B、C 组。