# 2026 暑期 Python 零基础学习路径

## 一、计划基本信息

- 学习周期：2026 年 7 月 20 日（周一）至 8 月 28 日（周五）
- 总周数：6 周
- 工作日学习天数：30 天
- 学生起点：零基础，默认没有安装过 Python，不熟悉文件路径、英文符号、终端和编程报错
- 最终目标：能够独立读懂、补全并运行名仕、科图、青娅三套 Python 真题，正确生成题目要求的 Excel 或 CSV 文件
- 固定课堂时间：每天 8:00-9:30，共 90 分钟
- 建议巩固时间：每天下午或晚间 60 分钟
- 建议错题复盘：每天 10-15 分钟
- 预计总投入：约 80 小时，其中课堂 45 小时、独立练习约 30 小时、诊断与复盘约 5 小时

本计划基于以下材料制定：

- [Python 真题知识点与考点详析](./python真题/Python真题知识点与考点详析.md)
- [第一周五天每日课件与练习](./第01周_7月20日-7月24日_零基础起步/README.md)

---

## 二、六周总体学习路径

```text
第 1 周：会安装、会运行、懂变量和基本数据类型
    ↓
第 2 周：会判断、循环、函数，能处理多条商品记录
    ↓
第 3 周：会使用 pandas 建表、选列、筛选、清洗和导出
    ↓
第 4 周：会使用 groupby、agg、占比和组内最大值完成商务统计
    ↓
第 5 周：会使用 requests、BeautifulSoup、JSON 和分页采集网页数据
    ↓
第 6 周：按“青娅 → 科图 → 名仕”的难度顺序完成三套真题
```

这一路径遵循四个原则：

1. **先会运行，再讲语法。** 零基础学生首先要解决文件、路径、解释器和运行问题。
2. **先用少量手工数据，再上 pandas。** 学生先理解“一条记录”和“多条记录”，再理解 DataFrame。
3. **先在本地数据上练分析，再连接网页。** 避免把网络问题和数据处理问题同时压给初学者。
4. **最后两周才进入完整采集和真题。** 前四周把真题中的每个难点拆成可独立完成的小任务。

---

## 三、每周内容总览

| 周次 | 日期 | 主题 | 本周结束时必须能够独立完成 |
|---|---|---|---|
| 第 1 周 | 7 月 20 日-7 月 24 日 | 零基础起步 | 创建并运行 `.py` 文件；区分四种基本类型；输入、转换并计算一条商品记录；从列表和字典取值 |
| 第 2 周 | 7 月 27 日-7 月 31 日 | 条件、循环、函数与结构化思维 | 使用 `if` 筛选数量大于 100 的商品；用 `for` 处理多条记录；读懂 `while` 分页；编写带参数和返回值的函数 |
| 第 3 周 | 8 月 3 日-8 月 7 日 | pandas 入门与数据清洗 | 创建 DataFrame；查看结构；选列、条件筛选、类型转换、缺失值处理、派生列计算；导出 CSV/Excel |
| 第 4 周 | 8 月 10 日-8 月 14 日 | pandas 分组统计与商务分析 | 使用 `groupby()`、`agg()`、`value_counts()`、布尔均值、`idxmax()`、排序和格式化完成汇总分析 |
| 第 5 周 | 8 月 17 日-8 月 21 日 | 网页、API 与数据采集 | 使用 GET/POST 请求；解析 HTML 表格和 JSON；理解请求头、编码、嵌套字典和分页；把网页数据转换为 DataFrame |
| 第 6 周 | 8 月 24 日-8 月 28 日 | 三套真题实战与综合测评 | 从题干出发独立完成青娅、科图、名仕题；正确生成 `result.csv`、`result1.csv`、`result2.csv` 和 `result.xlsx` |

---

## 四、每天统一的学习结构

除真题模拟日外，每天课堂采用以下固定节奏：

| 时间 | 环节 | 要求 |
|---|---|---|
| 8:00-8:10 | 无提示复现 | 不看教师投影，运行或重写昨天最核心的 3-8 行代码 |
| 8:10-8:25 | 概念讲解 | 每天最多引入 2-3 个新概念，必须联系真实商品或订单数据 |
| 8:25-8:50 | 教师逐步示范 | 每次新增少量代码，学生先预测结果，再运行 |
| 8:50-9:15 | 学生独立练习 | 教师不直接代写，只提供一级提示 |
| 9:15-9:25 | 错误修复 | 选择当天最常见的 1-2 个报错，全班一起定位 |
| 9:25-9:30 | 出门测 | 每人完成一个极小任务，作为当天是否掌握的证据 |

每天课后建议使用 60 分钟：

1. 10 分钟：不看答案重新运行课堂代码。
2. 30 分钟：完成当天必做练习。
3. 10 分钟：故意制造一个错误并修复。
4. 10 分钟：写“错误-原因-修复”记录。

学习记录统一采用三级：

- **独立完成**：不看答案、不问同学，能运行并解释。
- **提示后完成**：教师给出一句方向提示后完成。
- **未完成**：需要照抄或由他人直接修改。

只有“独立完成”才算真正掌握。

---

# 第一周：零基础起步

## 周期与定位

- 日期：7 月 20 日（周一）至 7 月 24 日（周五）
- 关键词：安装、路径、运行、变量、类型、输入、转换、列表、字典
- 对应真题切片：科图题“销售数量大于 100；销售总价 = 销售数量 × 商城价格”
- 教学边界：本周不要求独立掌握 pandas、网页采集或完整真题

## 本周知识清单

- 文件、文件夹、扩展名和路径
- Python、VS Code、解释器和终端的关系
- `pip install` 与 `import` 的区别
- `print()`、注释、英文括号和英文引号
- 变量与赋值
- `str`、`int`、`float`、`bool`
- `input()`、`int()`、`float()`
- 四则运算和比较运算
- f-string 与 `.2f`
- 列表、下标、字典、键和值
- `for` 和 `if` 只做初步带读

## 本周产物

```text
第01周/
├── hello.py
├── 包安装后检查.py
├── 变量与类型.py
├── 交互式销售额.py
├── 列表与字典.py
├── 真实案例逐行版.py
└── 周五诊断.py
```

## 7 月 20 日（周一）：安装、文件夹与第一次运行

### 当天目标

学生能够关闭并重新打开 VS Code，找到自己的 `hello.py`，独立保存、运行并看到输出。

### 课堂内容

| 时间 | 学习内容 | 学生活动 |
|---|---|---|
| 8:00-8:10 | 说明六周目标和课堂规则 | 建立个人学习记录表 |
| 8:10-8:25 | 文件、文件夹、扩展名、路径 | 建立 `D:\Python暑期训练\第01周` |
| 8:25-8:50 | 安装 Python，勾选 PATH | 使用版本命令检查安装 |
| 8:50-9:05 | 安装 VS Code 和 Python 扩展 | 选择正确解释器 |
| 9:05-9:20 | 创建并运行 `hello.py` | 逐字符输入两个 `print()` |
| 9:20-9:30 | 关闭后重新打开 | 独立完成保存和运行 |

### 必做练习

```python
print("我的姓名是：张三")
print("我的专业是：商务数据分析")
print("我的暑期目标是：独立完成 Python 真题")
```

### 故意制造的错误

- 删除右括号。
- 使用中文引号。
- 把 `print` 写成 `pirnt`。
- 修改后不保存就运行。

### 当日产物

- `hello.py`
- 第一条错误记录

### 过关标准

- 能指出代码文件的实际保存位置。
- 能区分编辑区和终端。
- 能独立完成“保存-运行-查看结果”。
- 报错时知道先看最后一行，不连续乱点运行。

## 7 月 21 日（周二）：终端、pip 与软件包

### 当天目标

学生知道终端命令与 Python 代码不是一回事，能使用当前解释器安装并检查软件包。

### 课堂内容

| 时间 | 学习内容 | 学生活动 |
|---|---|---|
| 8:00-8:15 | 无提示重新运行 `hello.py` | 记录环境问题学生 |
| 8:15-8:30 | 终端、提示符、当前路径 | 指出命令输入位置 |
| 8:30-8:45 | `python --version`、`python -m pip --version` | 逐词解释命令 |
| 8:45-9:05 | 安装 pandas、openpyxl、jupyter | 确保安装到当前解释器 |
| 9:05-9:20 | 使用 `import` 检查包 | 输出版本号 |
| 9:20-9:30 | 命令与代码分类测验 | 把 8 个示例放入正确位置 |

### 必做练习

```python
import pandas
import openpyxl

print("pandas 版本：", pandas.__version__)
print("openpyxl 版本：", openpyxl.__version__)
```

### 必须理解

- `pip` 负责安装。
- `import` 负责在程序中使用。
- 安装成功不等于当前 VS Code 选中了正确解释器。
- 终端命令不能原样写入 `.py` 文件。

### 当日产物

- `包安装后检查.py`
- 一张“终端命令/代码/输出”分类表

### 过关标准

- 能让检查脚本输出两个版本号。
- 遇到 `No module named ...` 时，先检查解释器而不是盲目重装。

## 7 月 22 日（周三）：变量与四种基本类型

### 当天目标

学生能读懂“变量名 = 值”，能判断文本、整数、小数和真假。

### 课堂内容

| 时间 | 学习内容 | 学生活动 |
|---|---|---|
| 8:00-8:10 | 环境和终端快问快答 | 独立运行包检查脚本 |
| 8:10-8:25 | 英文半角符号 | 输入引号、括号、等号、井号 |
| 8:25-8:40 | `print()` 和注释 | 修改内容、预测输出 |
| 8:40-9:00 | 变量、赋值、命名 | 创建商品名称、数量、价格变量 |
| 9:00-9:20 | `str/int/float/bool` 和 `type()` | 先猜类型再运行 |
| 9:20-9:30 | 真题微切片 | 判断数量是否大于 100 |

### 必做练习

```python
product_name = "双肩包"
quantity = 125
mall_price = 199.0
is_over_100 = quantity > 100

print(type(product_name))
print(type(quantity))
print(type(mall_price))
print(is_over_100)
```

### 边界实验

依次把数量改为：

```python
80
100
101
"125"
```

每次先预测类型和比较结果，再运行。

### 当日产物

- `变量与类型.py`
- 四种类型对照表

### 过关标准

- 能解释 `"125"` 和 `125` 的区别。
- 能解释 `=` 和 `==` 不是同一个符号。
- 能用 `type()` 检查任意变量。

## 7 月 23 日（周四）：输入、转换、计算与格式化

### 当天目标

学生能够输入一条商品记录，将文本转换为数字，计算销售总价并保留两位小数输出。

### 课堂内容

| 时间 | 学习内容 | 学生活动 |
|---|---|---|
| 8:00-8:15 | 类型卡片复习 | 判断 10 个值的类型 |
| 8:15-8:30 | `input()` | 输入商品名称并打印 |
| 8:30-8:50 | `int()` 和 `float()` | 对比转换前后类型 |
| 8:50-9:05 | 乘法和变量计算 | 手算后程序验证 |
| 9:05-9:20 | f-string 和 `.2f` | 修改显示位数 |
| 9:20-9:30 | 独立完成一组新数据 | 教师只检查结果 |

### 必做练习

```python
product_name = input("请输入商品名称：")
quantity = int(input("请输入销售数量："))
price = float(input("请输入商城价格："))
total_sales = quantity * price

print(f"商品：{product_name}")
print(f"销售总价：{total_sales:.2f} 元")
```

### 故意制造的错误

- 数量输入汉字。
- 价格输入空白。
- 不转换类型就尝试相乘。
- 删除 f-string 前的 `f`。

### 当日产物

- `交互式销售额.py`
- 3 组手算和程序结果对照

### 过关标准

- 能说出所有 `input()` 结果默认都是字符串。
- 能根据数量和价格的业务含义选择 `int()` 或 `float()`。
- 能解释 `.2f` 只控制显示格式。

## 7 月 24 日（周五）：列表、字典与第一周诊断

### 当天目标

学生能从列表按下标取值，从字典按键取值；能在教师引导下读懂 `for` 每轮处理哪条记录。

### 课堂内容

| 时间 | 学习内容 | 学生活动 |
|---|---|---|
| 8:00-8:15 | 独立复现交互式销售额 | 不看答案运行 |
| 8:15-8:35 | 列表和下标 | 练习 0、1、2 |
| 8:35-8:55 | 字典的键和值 | 建立一条商品记录 |
| 8:55-9:10 | `for` 循环带读 | 用手指跟踪当前记录 |
| 9:10-9:25 | 科图真题最小案例 | 修改数据并预测输出 |
| 9:25-9:30 | 5 分钟诊断 | 独立完成指定任务 |

### 必做练习

```python
products = [
    {"品名": "双肩包", "销售数量": 125, "商城价格": 199.0},
    {"品名": "帆布包", "销售数量": 80, "商城价格": 59.0},
]

for product in products:
    total_sales = product["销售数量"] * product["商城价格"]
    print(f"{product['品名']}：{total_sales:.2f} 元")
```

### 周诊断任务

1. 新建 `周五诊断.py`。
2. 创建品名、整数数量和小数价格。
3. 计算销售总价。
4. 使用 f-string 输出两位小数。
5. 从教师提供的字典中取出 `"销售数量"`。

### 分组标准

- A 组：5 分钟内全部独立完成。
- B 组：接受一句提示后完成。
- C 组：不能完成创建变量、计算或运行。

### 本周晋级标准

班级至少 80% 学生达到以下水平后，第二周才按正常进度进入判断和循环：

- 独立运行文件。
- 区分四种基本类型。
- 完成一条记录的销售总价计算。
- 从列表和字典取值。

未达标学生在第二周每天 7:45-8:00 参加补强，不直接跳过基础问题。

---

# 第二周：条件、循环、函数与结构化思维

## 周期与定位

- 日期：7 月 27 日（周一）至 7 月 31 日（周五）
- 关键词：比较、判断、循环、累计、函数、返回值、分页思维
- 对应真题：
  - 科图：筛选销售数量大于 100
  - 名仕：实际销量、实际销售额、`for` 店铺循环、`while` 分页
  - 三套题：自定义请求函数与解析函数

## 本周知识清单

- 比较运算：`>`、`>=`、`==`、`!=`
- 逻辑运算：`and`、`or`、`not`
- `if`、`elif`、`else`
- 边界值 99、100、101
- `for` 遍历列表和字典列表
- 累加变量与计数变量
- `while`、布尔标志、页码递增
- 函数定义、参数、返回值和调用
- 局部变量与函数外变量的初步区别
- `try/except` 的最小错误保护
- 拆解“输入-处理-输出”三段式程序

## 本周产物

```text
第02周/
├── 01_条件筛选.py
├── 02_多商品循环.py
├── 03_分页循环模型.py
├── 04_业务计算函数.py
├── 05_商品分析小项目.py
├── 周五诊断.py
└── 本周错误清单.md
```

## 7 月 27 日（周一）：比较运算与 `if` 条件筛选

### 当天目标

学生能够使用 `if` 只输出销售数量大于 100 的商品，并正确处理边界值 100。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:15 | 第一周补强与复现 | 重新计算一条商品销售额 |
| 8:15-8:30 | 比较运算符 | 手工判断 99、100、101 |
| 8:30-8:45 | `if`、冒号和缩进 | 只打印满足条件的商品 |
| 8:45-9:00 | `elif`、`else` | 分成高销量、普通、低销量 |
| 9:00-9:15 | 逻辑运算 | 同时满足数量和价格条件 |
| 9:15-9:30 | 独立练习和出门测 | 修改阈值，不看示例完成 |

### 核心代码

```python
quantity = 125

if quantity > 100:
    print("销售数量超过 100")
else:
    print("销售数量未超过 100")
```

### 必做练习

1. 分别测试数量 `99`、`100`、`101`。
2. 把条件从“超过 100”改成“不少于 100”。
3. 增加价格条件：数量超过 100 且价格不低于 50。
4. 用自己的话解释 `>` 和 `>=` 的区别。

### 当日产物

- `01_条件筛选.py`
- 一张边界值测试表

### 过关标准

- `if` 后有冒号。
- 条件代码块正确缩进。
- 能根据题干中的“以上”“大于”选择 `>=` 或 `>`。

## 7 月 28 日（周二）：`for` 循环处理多条记录

### 当天目标

学生能遍历商品字典列表，筛选满足条件的商品，并累计销售总价。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 无提示写出一个 `if` | 测试 100 的边界 |
| 8:10-8:25 | `for` 的执行顺序 | 纸面跟踪三轮循环 |
| 8:25-8:45 | 循环内字典取值 | 打印每条商品名称和数量 |
| 8:45-9:00 | `for + if` | 只保留数量大于 100 |
| 9:00-9:15 | 累加变量 | 求满足条件商品的销售总价 |
| 9:15-9:30 | 独立改写 | 增加合格商品计数 |

### 核心代码

```python
products = [
    {"品名": "双肩包", "销售数量": 125, "商城价格": 199.0},
    {"品名": "帆布包", "销售数量": 80, "商城价格": 59.0},
    {"品名": "拉杆箱", "销售数量": 160, "商城价格": 399.0},
]

qualified_count = 0
qualified_sales = 0.0

for product in products:
    if product["销售数量"] > 100:
        sales = product["销售数量"] * product["商城价格"]
        qualified_count = qualified_count + 1
        qualified_sales = qualified_sales + sales
        print(product["品名"], sales)

print("合格商品数：", qualified_count)
print("合格商品销售总价：", qualified_sales)
```

### 必须理解

- 累加变量必须在循环前初始化。
- 当前记录变量 `product` 每轮指向不同字典。
- 循环外的 `print()` 只执行一次。
- 循环内的 `print()` 每满足一次条件执行一次。

### 当日产物

- `02_多商品循环.py`
- 一张三轮循环跟踪表

### 过关标准

- 能口头说出每轮 `product` 的内容。
- 能区分当前商品销售额和全部商品销售总额。
- 能在不复制新循环的情况下再增加一个统计指标。

## 7 月 29 日（周三）：`while`、布尔标记与分页模型

### 当天目标

学生能读懂名仕题的分页逻辑，理解页码递增和结束条件，避免死循环。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 复现 `for + if` | 输出合格商品 |
| 8:10-8:25 | `while` 的适用场景 | 比较已知次数和未知页数 |
| 8:25-8:40 | 布尔标志 `flag` | 用真假控制循环 |
| 8:40-9:00 | 页码递增 | 模拟 1、2、3 页 |
| 9:00-9:15 | 结束条件和死循环 | 故意删除更新语句 |
| 9:15-9:30 | 名仕代码带读 | 找出店铺循环和分页循环 |

### 本地分页模型

```python
page_num = 1
has_next_page = True

while has_next_page:
    print("正在处理第", page_num, "页")

    if page_num >= 3:
        has_next_page = False

    page_num = page_num + 1
```

### 进阶模型

使用列表模拟服务器返回：

```python
pages = [
    {"list": ["商品A", "商品B"], "hasNextPage": True},
    {"list": ["商品C"], "hasNextPage": True},
    {"list": ["商品D"], "hasNextPage": False},
]
```

学生需要：

1. 按页输出商品。
2. 从字典中读取 `hasNextPage`。
3. 解释为什么切换店铺后页码要恢复为 1。

### 当日产物

- `03_分页循环模型.py`
- 一张“外层店铺/内层页面”流程图

### 过关标准

- 能指出哪个变量控制当前页。
- 能指出哪个变量控制是否继续。
- 能解释漏写页码更新为什么会重复请求。
- 不要求当天独立写出网络请求。

## 7 月 30 日（周四）：函数、参数与返回值

### 当天目标

学生能把业务计算封装成函数，能够区分“打印结果”和“返回结果”。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 复现分页模型 | 找到循环结束语句 |
| 8:10-8:25 | 为什么需要函数 | 找出重复计算代码 |
| 8:25-8:45 | `def`、参数和缩进 | 编写实际销量函数 |
| 8:45-9:00 | `return` | 把函数结果交回调用处 |
| 9:00-9:15 | 多参数函数 | 计算实际销售额 |
| 9:15-9:30 | 函数调用测试 | 使用 3 组数据验证 |

### 核心代码

```python
def calculate_actual_quantity(quantity, returns):
    actual_quantity = quantity - returns
    return actual_quantity


def calculate_actual_sales(quantity, returns, price):
    actual_quantity = calculate_actual_quantity(quantity, returns)
    actual_sales = actual_quantity * price
    return actual_sales
```

### 必须理解

- 函数定义时的参数是形式参数。
- 调用时传入的是实际数据。
- `return` 后的结果可以继续参与计算。
- `print()` 主要用于显示，不等于返回值。
- 函数名应体现用途。

### 必做练习

测试以下三组数据：

| 销量 | 退单量 | 售价 | 预期实际销量 |
|---:|---:|---:|---:|
| 100 | 5 | 20.0 | 95 |
| 80 | 0 | 59.0 | 80 |
| 10 | 12 | 100.0 | -2 |

第三组用于讨论：程序能算出负数，但业务上是否合理，需要数据质量检查。

### 当日产物

- `04_业务计算函数.py`
- 函数输入与输出说明表

### 过关标准

- 能独立写出一个带参数和 `return` 的函数。
- 能解释函数调用得到的结果保存在哪里。
- 能发现“能运行”不等于“业务结果一定合理”。

## 7 月 31 日（周五）：商品分析小项目与周诊断

### 当天目标

综合使用列表、字典、`if`、`for`、函数和累计变量，完成一个不依赖 pandas 的商品分析小项目。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 函数默写 | 写实际销量函数 |
| 8:10-8:25 | 读任务和列输入输出 | 不急着写代码 |
| 8:25-8:50 | 独立编写小项目 | 教师只给一级提示 |
| 8:50-9:05 | 增加异常输入保护 | 最小 `try/except` |
| 9:05-9:20 | 两人互测 | 每人提供一组边界数据 |
| 9:20-9:30 | 周诊断 | 保存最终版本 |

### 小项目要求

给定 4 条商品字典记录，程序需要：

1. 计算每条记录的实际销量。
2. 计算每条记录的实际销售额。
3. 只输出实际销量大于 100 的商品。
4. 统计这些商品的总销售额。
5. 把计算公式封装成函数。

### 周诊断评分

| 项目 | 分值 |
|---|---:|
| 能独立运行文件 | 10 |
| `for` 循环正确 | 20 |
| `if` 条件和边界正确 | 20 |
| 函数参数和返回值正确 | 20 |
| 实际销量、销售额公式正确 | 20 |
| 输出清楚、代码缩进正确 | 10 |

### 本周晋级标准

- 80 分及以上：正常进入 pandas。
- 60-79 分：第三周每天增加 15 分钟循环和函数补强。
- 60 分以下：第三周上午仍跟班，下午先完成第二周补做题，再进入 pandas 独立练习。

---

# 第三周：pandas 入门与数据清洗

## 周期与定位

- 日期：8 月 3 日（周一）至 8 月 7 日（周五）
- 关键词：Series、DataFrame、选列、筛选、类型、缺失值、新列、拼接、索引、导出
- 对应真题：
  - 三套题都需要把数据转换为 DataFrame
  - 青娅：`.loc[]`、`.isin()`、`.round()`、`.fillna()`
  - 名仕：类型转换、实际销量、实际销售额、`concat()`、`reset_index()`
  - 科图：选取大量指定字段

## 本周教学策略

本周暂不连接网页。所有数据先在本地通过列表、字典、CSV 或 Excel 提供，确保学生能够把注意力集中在 pandas。

## 本周产物

```text
第03周/
├── data/
│   ├── 商品数据.csv
│   ├── 商品数据_含错误值.csv
│   └── 现金流量表.csv
├── 01_DataFrame入门.py
├── 02_选列与筛选.py
├── 03_类型与缺失值.py
├── 04_派生指标.py
├── 05_合并排序与导出.py
├── result.csv
├── result.xlsx
└── 周五诊断.py
```

## 8 月 3 日（周一）：Series、DataFrame 与结构查看

### 当天目标

学生能够从字典列表创建 DataFrame，并使用固定检查命令了解数据形状、列名、前几行和类型。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 第二周函数复现 | 计算一条实际销售额 |
| 8:10-8:25 | 一维 Series 与二维 DataFrame | 用纸表格对应行列 |
| 8:25-8:45 | `pd.DataFrame()` | 字典列表转表 |
| 8:45-9:00 | `head()`、`shape`、`columns` | 建立数据检查顺序 |
| 9:00-9:15 | `dtypes` 和索引 | 判断哪些列不能直接计算 |
| 9:15-9:30 | 独立建立新表 | 添加一条商品记录 |

### 核心代码

```python
import pandas as pd

records = [
    {"商品名称": "双肩包", "销量": 120, "退单量": 5, "售价": 199.0},
    {"商品名称": "帆布包", "销量": 80, "退单量": 2, "售价": 59.0},
]

df = pd.DataFrame(records)

print(df.head())
print(df.shape)
print(df.columns.tolist())
print(df.dtypes)
```

### 固定检查口令

以后每得到一个新 DataFrame，先回答：

1. 有多少行、多少列？
2. 列名是什么？
3. 前几行是否符合预期？
4. 每一列是什么类型？
5. 是否存在空值？

### 当日产物

- `01_DataFrame入门.py`
- 一张 Series/DataFrame/列表/字典对照表

### 过关标准

- 能区分 DataFrame 的行和列。
- 能解释 `shape` 返回的两个数字。
- 能独立打印列名和数据类型。

## 8 月 4 日（周二）：选列、`.loc[]` 与条件筛选

### 当天目标

学生能选取一列或多列，使用 `.loc[]`、`.isin()` 和组合条件筛选记录。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | DataFrame 五项检查 | 无提示输出结构 |
| 8:10-8:25 | 单中括号和双中括号 | 比较 Series 与 DataFrame |
| 8:25-8:45 | 布尔条件和 `.loc[]` | 筛选销量大于 100 |
| 8:45-9:00 | `.isin()` | 筛选第 1、2 季度 |
| 9:00-9:15 | `&`、`|` 和括号 | 年度与季度组合筛选 |
| 9:15-9:30 | 中文列名精确匹配 | 故意制造列名错误 |

### 核心代码

```python
selected = df[["商品名称", "销量", "售价"]]

high_sales = df.loc[df["销量"] > 100]

first_two_quarters = df.loc[
    (df["年度"] == 2024)
    & (df["季度"].isin([1, 2]))
].copy()
```

### 必做练习

1. 只保留“商品名称、销量、退单量、售价”。
2. 筛选退单量不为 0 的记录。
3. 筛选 2024 年第 1、2 季度。
4. 用 `.isin()` 筛选两个指定现金流项目。
5. 故意把中文冒号 `：` 改成英文冒号 `:`，观察匹配结果。

### 当日产物

- `02_选列与筛选.py`
- 一张单列/多列/行列同时筛选对照表

### 过关标准

- 知道 `df["列"]` 通常返回 Series。
- 知道 `df[["列"]]` 返回 DataFrame。
- Series 条件组合使用 `&`、`|`，不用普通 `and`、`or`。
- 多个条件分别加圆括号。

## 8 月 5 日（周三）：类型转换、缺失值与小数处理

### 当天目标

学生能够识别“看起来像数字的文本”，使用 `pd.to_numeric()` 转换并处理非法值和缺失值。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 条件筛选复现 | 筛选 2024 年 1-2 季度 |
| 8:10-8:25 | `object` 类型的含义 | 检查含错误值数据 |
| 8:25-8:45 | `astype()` 与 `to_numeric()` | 比较严格和容错转换 |
| 8:45-9:00 | `NaN` 和 `fillna()` | 讨论填 0 的业务含义 |
| 9:00-9:15 | `round(2)` | 区分数值舍入和显示格式 |
| 9:15-9:30 | 独立清洗三列 | 输出清洗前后类型 |

### 核心代码

```python
df["销量"] = pd.to_numeric(df["销量"], errors="coerce")
df["退单量"] = pd.to_numeric(df["退单量"], errors="coerce")
df["售价"] = pd.to_numeric(df["售价"], errors="coerce")

print(df.isna().sum())

df["退单量"] = df["退单量"].fillna(0)
df["售价"] = df["售价"].round(2)
```

### 必做对比

- `"125"` 转为数值。
- 空字符串转为 `NaN`。
- `"未知"` 转为 `NaN`。
- `astype(int)` 遇到空值时的报错。
- `12.3` 在 DataFrame 中与导出为 `12.30` 的区别。

### 当日产物

- `03_类型与缺失值.py`
- 清洗规则表：字段、原类型、目标类型、错误值处理方式

### 过关标准

- 能解释 `errors="coerce"`。
- 不会无理由把所有空值都填成 0。
- 能解释 `.round(2)` 不一定保留尾随 0 的显示。

## 8 月 6 日（周四）：新列、向量化、`apply()` 和 `lambda`

### 当天目标

学生能计算实际销量和实际销售额，理解向量化运算与逐行 `apply(axis=1)`。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 类型清洗复现 | 清洗销量、退单量、售价 |
| 8:10-8:25 | DataFrame 列之间运算 | 创建实际销量 |
| 8:25-8:40 | 连续创建派生指标 | 创建实际销售额 |
| 8:40-9:00 | `apply()` 和 `axis=1` | 逐行读取两个字段 |
| 9:00-9:15 | `lambda` | 拆解输入和返回表达式 |
| 9:15-9:30 | 对比两种写法 | 说明优先使用向量化 |

### 向量化写法

```python
df["实际销量"] = df["销量"] - df["退单量"]
df["实际销售额"] = df["实际销量"] * df["售价"]
```

### 真题结构写法

```python
df["实际销量"] = df.apply(
    lambda row: row["销量"] - row["退单量"],
    axis=1
)
```

### 必须理解

- `axis=1` 表示逐行。
- `row` 是当前行对应的 Series。
- `apply()` 能解决复杂逐行逻辑，但简单列运算优先使用向量化。
- 新指标之间有先后依赖：先实际销量，后实际销售额。

### 当日产物

- `04_派生指标.py`
- 两种写法运行结果对照

### 过关标准

- 能独立写出两个业务公式。
- 能解释为什么销售额使用实际销量而不是原销量。
- `apply()` 中没有漏写 `axis=1`。

## 8 月 7 日（周五）：合并、索引、排序和文件导出

### 当天目标

学生能合并两个同结构 DataFrame，整理索引和列顺序，排序并导出 CSV 与 Excel。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 派生指标默写 | 不看答案写两行 |
| 8:10-8:25 | `pd.concat()` | 合并两个季度 |
| 8:25-8:40 | 索引和 `reset_index()` | 观察重复索引 |
| 8:40-8:55 | `rename()` 和列顺序 | 整理输出表 |
| 8:55-9:10 | `sort_values()` | 升序和降序对比 |
| 9:10-9:25 | `to_csv()`、`to_excel()` | 生成并打开文件 |
| 9:25-9:30 | 周诊断 | 检查结果文件 |

### 核心代码

```python
all_data = pd.concat([df_q1, df_q2], ignore_index=True)
all_data = all_data.sort_values(
    by="实际销售额",
    ascending=True
).reset_index(drop=True)

all_data.to_csv(
    "result.csv",
    index=False,
    encoding="utf_8_sig"
)

all_data.to_excel(
    "result.xlsx",
    index=False
)
```

### 周诊断

给一份含以下问题的商品表：

- 数量列有数字文本；
- 退单量有空值；
- 数据分成两个季度文件；
- 要求计算两个派生指标；
- 筛选 2024 年第 1、2 季度；
- 按实际销售额升序；
- 同时导出 CSV 和 Excel。

### 本周晋级标准

| 能力 | 必须达到 |
|---|---|
| 数据检查 | 独立使用 `head/shape/columns/dtypes/isna` |
| 筛选 | 独立使用 `.loc[]` 和 `.isin()` |
| 清洗 | 能完成数值转换和缺失值处理 |
| 计算 | 能创建实际销量、实际销售额 |
| 输出 | 能生成无多余索引的 CSV 和 Excel |

周诊断达到 80 分后进入分组统计。

---

# 第四周：pandas 分组统计与商务分析

## 周期与定位

- 日期：8 月 10 日（周一）至 8 月 14 日（周五）
- 关键词：分组、聚合、占比、布尔均值、组内最大值、重命名、格式化
- 对应真题：
  - 名仕：按网店汇总实际销量、销售总额和平均价格
  - 科图：按年度和区域统计付款方式占比并选择最大者
  - 科图：按年度和客户类型统计女性占比与平均年龄

## 本周学习难点

本周最重要的不是背函数，而是先确定数据粒度：

- 原始表一行代表什么？
- 最终结果一行代表什么？
- 应按哪个字段或哪些字段分组？
- 每个指标应该求和、求平均还是求比例？

## 本周产物

```text
第04周/
├── 01_单字段分组.py
├── 02_多指标聚合.py
├── 03_分类占比.py
├── 04_组内Top1与客户画像.py
├── 05_商务分析综合项目.py
├── result1.csv
├── result2.csv
├── result.xlsx
└── 周五诊断.py
```

## 8 月 10 日（周一）：单字段 `groupby()` 与求和、均值

### 当天目标

学生能够按网店名称分组，分别计算销量总和、销售额总和和售价平均值。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 第三周清洗复现 | 生成实际销量和实际销售额 |
| 8:10-8:25 | 原始粒度与汇总粒度 | 用卡片按店铺分堆 |
| 8:25-8:45 | `groupby()` | 创建店铺分组对象 |
| 8:45-9:00 | `sum()` | 汇总实际销量 |
| 9:00-9:15 | `mean()` | 计算平均售价 |
| 9:15-9:30 | 人工核对 | 手算一个店铺与程序比较 |

### 核心代码

```python
grouped = df.groupby("网店名称")

quantity_total = grouped["实际销量"].sum()
sales_total = grouped["实际销售额"].sum()
price_mean = grouped["售价"].mean()
```

### 必须理解

- `groupby()` 本身不是最终结果。
- `sum()` 和 `mean()` 的业务含义不同。
- 平均售价默认是记录的简单平均，不一定是销量加权平均。
- 分组字段默认成为结果索引。

### 当日产物

- `01_单字段分组.py`
- 一张手工分组核对表

### 过关标准

- 能用一句话说清“结果表的一行代表一家网店”。
- 能选择正确的求和或平均函数。
- 至少人工核对一个分组。

## 8 月 11 日（周二）：`agg()` 多指标聚合与结果整理

### 当天目标

学生能一次完成多个指标聚合，并使用 `rename()`、`reset_index()` 和列顺序整理结果。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 单字段分组复现 | 分别求和与均值 |
| 8:10-8:30 | `agg()` 字典 | 列名对应统计函数 |
| 8:30-8:45 | 多指标同时输出 | 对照昨天三个结果 |
| 8:45-9:00 | `rename()` | 改成业务列名 |
| 9:00-9:15 | `reset_index()` | 把店铺名还原为普通列 |
| 9:15-9:30 | 列重排和取整 | 形成名仕目标表 |

### 核心代码

```python
totals = (
    df.groupby("网店名称")
    .agg({
        "实际销量": "sum",
        "实际销售额": "sum",
        "售价": "mean",
    })
    .rename(columns={
        "实际销售额": "销售总额",
        "售价": "平均价格",
    })
    .reset_index()
)

totals = totals[["网店名称", "平均价格", "实际销量", "销售总额"]]
```

### 必做练习

1. 增加商品记录数。
2. 比较 `groupby(..., as_index=False)` 与 `reset_index()`。
3. 对销售总额和平均价格保留 0 位小数。
4. 按销售总额升序。

### 当日产物

- `02_多指标聚合.py`
- 名仕汇总表本地数据版本

### 过关标准

- 能根据业务描述写出聚合字典。
- 能解释分组字段为什么曾经出现在索引。
- 能整理出指定列顺序。

## 8 月 12 日（周三）：`value_counts()` 与分类占比

### 当天目标

学生能按“年 + 区域”分组，计算各付款方式的组内占比。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | `agg()` 默写 | 完成三个指标聚合 |
| 8:10-8:25 | 次数、比例、百分比 | 手算一个小组 |
| 8:25-8:45 | `value_counts()` | 统计付款方式次数 |
| 8:45-9:00 | `normalize=True` | 转为组内比例 |
| 9:00-9:15 | `* 100`、`rename()`、`reset_index()` | 形成占比表 |
| 9:15-9:30 | 分母核验 | 手算对比程序结果 |

### 核心代码

```python
result = (
    df.groupby(["年", "区域分布"])["付款方式"]
    .value_counts(normalize=True)
    .mul(100)
    .rename("占比")
    .reset_index()
)
```

### 必须理解

- 分组单位是“某一年中的某个区域”。
- `value_counts()` 统计组内每个付款方式。
- `normalize=True` 的分母是当前组的有效记录数。
- 乘 100 后才是百分数。
- 缺失付款方式默认不会计数。

### 当日产物

- `03_分类占比.py`
- 一张至少包含两个年份、两个区域的手算核对表

### 过关标准

- 每个“年 + 区域”组的占比合计接近 100%。
- 能解释为什么不能只按“年”分组。

## 8 月 13 日（周四）：组内 Top 1、布尔均值与平均年龄

### 当天目标

学生能够保留每个年度、区域中占比最高的付款方式，并统计女性占比和平均年龄。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | 占比代码复现 | 输出全部付款方式占比 |
| 8:10-8:25 | `max()` 与 `idxmax()` | 比较“值”和“整行” |
| 8:25-8:40 | `.loc[idxmax]` | 每组保留 Top 1 |
| 8:40-8:55 | 布尔值均值 | 手算女性占比 |
| 8:55-9:10 | `agg()` 混合匿名函数和均值 | 统计客户画像 |
| 9:10-9:20 | 并列第一和缺失值 | 讨论口径 |
| 9:20-9:30 | 独立完成 | 生成两个结果表 |

### 组内最大值

```python
top_payment = result.loc[
    result.groupby(["年", "区域分布"])["占比"].idxmax()
]
```

### 客户画像

```python
customer_result = (
    df.groupby(["年", "客户类型"])
    .agg({
        "性别": lambda x: (x == "女").mean() * 100,
        "年龄": "mean",
    })
    .rename(columns={
        "性别": "女性占比",
        "年龄": "平均年龄",
    })
    .reset_index()
)
```

### 必须理解

- `max()` 只有最大数值，`idxmax()` 给出最大值所在索引。
- `.loc[]` 使用索引取完整行。
- 布尔序列中 `True` 相当于 1，`False` 相当于 0。
- `astype(int)` 是截断，不是四舍五入。
- 并列最大值时 `idxmax()` 通常只保留第一条。

### 当日产物

- `04_组内Top1与客户画像.py`
- `result1.csv` 和 `result2.csv` 的本地数据版本

### 过关标准

- 每个“年 + 区域”最多保留一行。
- 女性占比处于 0%-100%。
- 能说明平均年龄采用截断还是四舍五入。

## 8 月 14 日（周五）：商务分析综合项目

### 当天目标

在不连接网页的情况下，完整复现名仕和科图的数据处理部分。

### 上午 90 分钟

| 时间 | 任务 |
|---|---|
| 8:00-8:15 | 阅读题目，标出输入字段、分组字段、计算公式和输出文件 |
| 8:15-8:45 | 完成名仕本地数据汇总 |
| 8:45-9:10 | 完成科图区域付款方式统计 |
| 9:10-9:25 | 完成科图客户类型统计 |
| 9:25-9:30 | 保存中间结果 |

### 课后 90 分钟综合作业

1. 不看课堂代码，从空白文件重新完成。
2. 输出：
   - `result.xlsx`
   - `result1.csv`
   - `result2.csv`
3. 打开三个结果文件逐项核验。
4. 提交一张结果截图和错误记录。

### 周诊断评分

| 项目 | 分值 |
|---|---:|
| 选列和类型转换 | 15 |
| 派生指标 | 15 |
| `groupby + agg` | 20 |
| 分类占比 | 15 |
| 组内最大值 | 15 |
| 女性占比和平均年龄 | 10 |
| 排序、格式化、导出 | 10 |

### 本周晋级标准

- 80 分以上：进入网页采集。
- 60-79 分：第五周上午学习采集，下午继续补 pandas。
- 60 分以下：先完成本地综合项目，不允许直接照抄完整网页采集答案。

---

# 第五周：网页、API 与数据采集

## 周期与定位

- 日期：8 月 17 日（周一）至 8 月 21 日（周五）
- 关键词：开发者工具、GET、POST、headers、encoding、HTML、BeautifulSoup、JSON、分页
- 对应真题：
  - 科图、青娅：GET + HTML 表格
  - 名仕：POST API + JSON + 分页

## 本周教学原则

1. 每个网络例子都准备本地 HTML 或 JSON 备份。
2. 网络不可用时继续学习解析，不把网络故障误判为语法错误。
3. 先打印和检查响应，再进入 pandas。
4. 先学 GET/HTML，再学 POST/JSON，最后学分页。

## 本周新增软件包

```text
python -m pip install requests beautifulsoup4 lxml html5lib
```

安装后检查：

```python
import requests
from bs4 import BeautifulSoup
import pandas as pd

print("网页采集环境准备完成")
```

## 本周产物

```text
第05周/
├── data/
│   ├── 示例网页.html
│   ├── 示例响应.json
│   └── 分页响应/
├── 01_GET请求.py
├── 02_HTML表格解析.py
├── 03_POST与JSON.py
├── 04_API分页采集.py
├── 05_采集分析综合项目.py
└── 周五诊断.py
```

## 8 月 17 日（周一）：浏览器开发者工具与 GET 请求

### 当天目标

学生能判断一个数据来自网页 HTML 还是 Network 中的接口，能发起 GET 请求并检查响应。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | pandas 综合复现 | 读取本地 CSV |
| 8:10-8:25 | URL、网页、服务器、响应 | 画请求-响应图 |
| 8:25-8:40 | 开发者工具 Elements | 查找 `<table>` |
| 8:40-8:55 | Network 与 Fetch/XHR | 找请求地址和方法 |
| 8:55-9:10 | `requests.get()` | 下载测试网页 |
| 9:10-9:20 | `status_code`、`text` | 检查响应 |
| 9:20-9:30 | User-Agent 和超时 | 完成安全模板 |

### 核心代码

```python
import requests

headers = {
    "user-agent": "Mozilla/5.0"
}

response = requests.get(
    url,
    headers=headers,
    timeout=20
)
response.raise_for_status()
response.encoding = "utf-8"

html = response.text
print(html[:300])
```

### 必须理解

- `response` 是响应对象，`response.text` 才是网页文本。
- `status_code == 200` 通常表示 HTTP 请求成功。
- `raise_for_status()` 能提前暴露 4xx/5xx 错误。
- `timeout` 防止无限等待。
- User-Agent 是请求头字段。

### 当日产物

- `01_GET请求.py`
- 一张开发者工具字段记录表：URL、Method、Headers、Payload、Response

### 过关标准

- 能从 Network 中找到 Request URL 和 Request Method。
- 能区分 HTML 文本和 JSON 响应。
- 网络失败时会使用本地备份继续练习。

## 8 月 18 日（周二）：BeautifulSoup 与 HTML 表格解析

### 当天目标

学生能使用 BeautifulSoup 找到网页中的全部 `<table>`，并用 `pd.read_html()` 转为 DataFrame。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | GET 模板复现 | 输出状态码和前 100 字符 |
| 8:10-8:25 | HTML 标签结构 | 认识 table/tr/th/td |
| 8:25-8:40 | BeautifulSoup | 创建解析对象 |
| 8:40-8:55 | `find_all("table")` | 统计表格数量 |
| 8:55-9:10 | `pd.read_html()` | 观察返回列表 |
| 9:10-9:20 | 合并多张表 | 使用 `pd.concat()` |
| 9:20-9:30 | 列名检查 | 输出 columns 和 head |

### 核心代码

```python
from io import StringIO
from bs4 import BeautifulSoup
import pandas as pd

soup = BeautifulSoup(html, "html.parser")
tables = soup.find_all("table")

df_list = []

for table in tables:
    parsed_tables = pd.read_html(StringIO(str(table)))
    df_list.extend(parsed_tables)

df = pd.concat(df_list, ignore_index=True)
```

### 必须理解

- `find_all()` 返回标签列表。
- `pd.read_html()` 返回 DataFrame 列表。
- 两种“列表”中的元素类型不同。
- 抓取后先检查 `shape`、`columns`、`head()`。
- 如果数据由 JavaScript 异步加载，静态 HTML 可能没有目标表。

### 当日产物

- `02_HTML表格解析.py`
- 本地网页解析结果 CSV

### 过关标准

- 能解释为什么 `read_html()` 后还要处理列表。
- 能合并两张同结构 HTML 表。
- 列名乱码时会先检查响应编码。

## 8 月 19 日（周三）：POST、JSON 与嵌套字典

### 当天目标

学生能够理解名仕 API 的请求体和 JSON 响应，正确读取嵌套的 `data/list/hasNextPage`。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | HTML 解析复现 | 合并两张表 |
| 8:10-8:25 | GET 与 POST 对比 | 判断参数放在哪里 |
| 8:25-8:40 | JSON 与 Python 字典 | 查看本地响应文件 |
| 8:40-8:55 | `json.dumps()` 与 `json=` | 比较两种请求体写法 |
| 8:55-9:10 | `response.json()` | 解析响应 |
| 9:10-9:20 | 嵌套字典取值 | 读取 list 和 hasNextPage |
| 9:20-9:30 | DataFrame 转换 | JSON 记录列表转表 |

### 推荐请求写法

```python
response = requests.post(
    api_url,
    json=request_data,
    headers=headers,
    timeout=20
)
response.raise_for_status()
result = response.json()
```

### 嵌套取值

```python
records = result["data"]["list"]
has_next_page = result["data"]["hasNextPage"]
df = pd.DataFrame(records)
```

### 必须理解

- JSON 对象通常对应 Python 字典。
- JSON 数组通常对应 Python 列表。
- `json=request_data` 会自动序列化请求体。
- `data=json.dumps(request_data)` 是参考代码中的另一种写法。
- 键层级错误会触发 `KeyError`。

### 当日产物

- `03_POST与JSON.py`
- 一张名仕响应结构树

### 过关标准

- 能从本地 JSON 中独立取出商品记录列表。
- 能说明 `list` 和 `hasNextPage` 的用途不同。
- 能把记录列表转换为 DataFrame。

## 8 月 20 日（周四）：API 分页与多店铺采集

### 当天目标

学生能把第二周的分页循环与本周的 API 请求结合，完成多页、多店铺数据收集。

### 课堂安排

| 时间 | 内容 | 课堂任务 |
|---|---|---|
| 8:00-8:10 | JSON 嵌套取值复现 | 读取 list 和下一页标记 |
| 8:10-8:25 | 分页请求参数 | 识别 pageNum、pageSize |
| 8:25-8:45 | `while` 请求页面 | 每页转 DataFrame |
| 8:45-9:00 | 列表收集与 concat | 合并全部页 |
| 9:00-9:15 | 外层店铺 `for` | 每家店从第 1 页开始 |
| 9:15-9:25 | 空列表和异常保护 | 避免 concat 空列表 |
| 9:25-9:30 | 口头流程复述 | 不看代码讲完整流程 |

### 核心框架

```python
all_pages = []

for shop in shop_list:
    goods_req["clvalue"] = shop["网店名称"]
    goods_req["pageNum"] = 1
    has_next_page = True

    while has_next_page:
        result = get_data_by_api(goods_list_api, goods_req)
        records = result["data"]["list"]

        if records:
            all_pages.append(pd.DataFrame(records))

        has_next_page = result["data"]["hasNextPage"]
        goods_req["pageNum"] = goods_req["pageNum"] + 1

if all_pages:
    df = pd.concat(all_pages, ignore_index=True)
else:
    df = pd.DataFrame()
```

### 必须理解

- 每家店铺开始前重置页码。
- `hasNextPage` 决定是否继续。
- 页码必须在循环中递增。
- 空页面不能盲目加入统计。
- 网络重试可能产生重复数据，要有去重意识。

### 当日产物

- `04_API分页采集.py`
- 多店铺、多页面流程图

### 过关标准

- 能指出外层和内层循环各自的职责。
- 能解释三种常见错误：死循环、漏页、重复第一页。
- 能在本地模拟响应上独立跑通。

## 8 月 21 日（周五）：采集与分析综合项目

### 当天目标

完成“采集-解析-DataFrame-分析-导出”的最小闭环，为下周真题做准备。

### 上午 90 分钟

| 时间 | 任务 |
|---|---|
| 8:00-8:15 | 阅读任务，判断 HTML 模式还是 API 模式 |
| 8:15-8:40 | 完成请求与解析 |
| 8:40-9:00 | 检查 DataFrame 结构和类型 |
| 9:00-9:20 | 完成一个分组统计 |
| 9:20-9:30 | 导出并打开结果 |

### 下午 90 分钟周诊断

提供两份材料：

1. 一个本地 HTML 页面，要求提取表格并筛选指定行。
2. 一个分页 JSON 响应包，要求合并所有页面并计算实际销售额。

学生必须先完成本地版本；网络在线版本作为加分项。

### 周诊断评分

| 项目 | 分值 |
|---|---:|
| 能判断 HTML/API 数据源 | 10 |
| GET 或 POST 使用正确 | 15 |
| 响应解析正确 | 20 |
| DataFrame 合并正确 | 15 |
| 筛选或统计正确 | 20 |
| 输出文件正确 | 10 |
| 状态码、超时、空数据检查 | 10 |

### 本周晋级标准

- 80 分以上：第六周按标准真题节奏。
- 60-79 分：真题日上午跟做，下午必须闭卷重做。
- 60 分以下：先使用本地备份完成题目数据处理部分，再补网页请求。

---

# 第六周：三套真题实战与综合测评

## 周期与定位

- 日期：8 月 24 日（周一）至 8 月 28 日（周五）
- 关键词：读题、拆解、独立补全、运行验证、文件核验、限时模拟
- 真题顺序：青娅 -> 科图 -> 名仕
- 排序依据：
  - 青娅的数据处理最集中，适合作为完整真题起点。
  - 科图增加多字段分组、占比和组内最大值。
  - 名仕增加 POST API、多店铺和分页，是综合难度最高的一套。

## 真题日统一作答流程

每套题都必须按以下顺序完成：

1. 圈出题目要求的输入字段。
2. 写出输出文件名。
3. 写出业务公式。
4. 标出数据源是 HTML 还是 API。
5. 先补会确定的空位。
6. 请求或读取数据后立即打印 `shape/columns/head/dtypes`。
7. 分阶段运行，不一次写完整段后才测试。
8. 导出后实际打开结果文件。
9. 对照题干逐条打勾。
10. 最后才查看参考代码。

## 8 月 24 日（周一）：青娅真题

### 当天目标

独立完成青娅题中的网页表格解析、四列选择、项目筛选、年度金额处理和 CSV 导出。

### 上午 90 分钟

| 时间 | 任务 |
|---|---|
| 8:00-8:10 | 闭卷写出 GET + HTML 表格解析框架 |
| 8:10-8:20 | 阅读青娅题干，列出输入、处理、输出 |
| 8:20-8:45 | 完成网页请求和表格合并 |
| 8:45-9:05 | 选取项目和三个年度列，使用 `.isin()` 筛选 |
| 9:05-9:20 | `round(2)`、缺失值处理和单列提取 |
| 9:20-9:30 | 导出 `result.csv` 并初步核验 |

### 下午 90 分钟

1. 从空白文件重新完成，不查看上午代码。
2. 增加 `.copy()`。
3. 使用 `float_format="%.2f"` 检查尾随 0。
4. 检查“变动金额求和”是否真的需要 `.sum()`。
5. 测试项目名中全角冒号和前后空格。

### 当日产物

```text
第06周/青娅/
├── 青娅_第一次作答.py
├── 青娅_闭卷重做.py
├── result.csv
└── 青娅错题记录.md
```

### 过关标准

- 四个列名和顺序正确。
- `.isin()` 使用正确。
- 能解释 `fillna(0)` 和补足两位小数不是同一件事。
- `result.csv` 无多余索引，中文打开正常。

## 8 月 25 日（周二）：科图真题

### 当天目标

独立完成 HTML 表格解析、区域付款方式占比、组内 Top 1、女性占比和平均年龄统计。

### 上午 90 分钟

| 时间 | 任务 |
|---|---|
| 8:00-8:10 | 无提示写出 HTML 解析函数 |
| 8:10-8:20 | 阅读题干，指出题干与代码任务的不一致 |
| 8:20-8:35 | 获取数据并选取指定字段 |
| 8:35-8:55 | 完成付款方式占比 |
| 8:55-9:10 | 使用 `idxmax()` 保留每组最大付款方式 |
| 9:10-9:22 | 完成女性占比和平均年龄 |
| 9:22-9:30 | 导出两个 CSV |

### 下午 90 分钟

1. 不看答案重做统计部分。
2. 人工核对一个“年 + 区域”组的占比。
3. 制造并列第一，观察 `idxmax()` 的行为。
4. 比较平均年龄 `astype(int)` 和 `round().astype(int)`。
5. 检查题干中的“数量大于 100”和“销售总价”是否属于实际评分点。

### 当日产物

```text
第06周/科图/
├── 科图_第一次作答.py
├── 科图_闭卷重做.py
├── result1.csv
├── result2.csv
└── 科图错题记录.md
```

### 过关标准

- 每个年度、区域只保留占比最大的一种付款方式。
- 百分比先计算和选最大值，最后才格式化为字符串。
- 女性占比公式正确。
- 两个输出文件名、编码和列顺序正确。

## 8 月 26 日（周三）：名仕真题

### 当天目标

完成 POST API、店铺循环、商品分页、DataFrame 清洗、业务指标计算、店铺汇总和 Excel 导出。

### 上午 90 分钟

| 时间 | 任务 |
|---|---|
| 8:00-8:12 | 阅读题干，画出店铺与页面两层循环 |
| 8:12-8:30 | 补全 POST 请求函数 |
| 8:30-8:50 | 补全店铺参数、页码和分页结束条件 |
| 8:50-9:05 | 合并数据、重置索引、选列和类型转换 |
| 9:05-9:18 | 计算实际销量和实际销售额 |
| 9:18-9:30 | 建立分组聚合框架并保存 |

### 下午 120 分钟

1. 完成 `groupby + agg`。
2. 重命名和调整列顺序。
3. 销售总额与平均价格取整。
4. 按销售总额升序。
5. 导出 `result.xlsx`。
6. 补充 2024 年第 1、2 季度显式筛选。
7. 检查空列表、重复索引、类型转换失败和负实际销量。

### 当日产物

```text
第06周/名仕/
├── 名仕_第一次作答.py
├── 名仕_改进版.py
├── result.xlsx
└── 名仕错题记录.md
```

### 过关标准

- 能解释外层店铺循环和内层分页循环。
- 每家店从第 1 页开始。
- 实际销量、实际销售额公式正确。
- 聚合函数与业务指标对应正确。
- 结果按销售总额升序。

## 8 月 27 日（周四）：综合限时模拟与错题修复

### 当天目标

在不查看参考答案的情况下完成一套混合模拟题，并根据运行证据定位错误。

### 模拟题结构

题目提供：

- 一个 HTML 表格数据源；
- 一个 JSON 分页数据源；
- 商品、年度、区域、付款方式、性别、年龄等字段；
- 2 个结果文件要求。

学生需完成：

1. 判断两个数据源各用什么方法获取。
2. 合并数据。
3. 清洗数值列。
4. 计算一个派生指标。
5. 完成一个分组总额。
6. 完成一个分类占比。
7. 选出组内最大类别。
8. 导出 CSV 和 Excel。

### 上午 90 分钟

- 10 分钟读题和设计。
- 60 分钟独立编程。
- 15 分钟结果检查。
- 5 分钟提交。

### 下午 90 分钟

按错误类型修复，不允许整段替换：

| 错误类别 | 修复方法 |
|---|---|
| 语法错误 | 从报错最后一行检查括号、引号、冒号和缩进 |
| 列名错误 | 打印 `df.columns.tolist()` |
| 类型错误 | 打印 `df.dtypes` 和异常值 |
| 空结果 | 分阶段打印筛选前后的行数 |
| 分组口径错误 | 用少量数据手算一个组 |
| 排序错误 | 格式化前检查指标类型 |
| 导出错误 | 打印当前路径并打开结果文件 |

### 当日产物

- `综合模拟_原始作答.py`
- `综合模拟_修复版.py`
- `综合模拟错误归因.md`
- 两个结果文件

### 过关标准

- 120 分钟内完成核心流程。
- 至少 80% 输出字段和值正确。
- 能根据证据自行修复至少 3 个错误。

## 8 月 28 日（周五）：最终测评与个人后续路径

### 上午最终测评

总时间建议 120 分钟；如只能使用 90 分钟，则减少数据量但不减少流程。

#### 测评结构

| 模块 | 分值 |
|---|---:|
| 环境、文件和运行 | 5 |
| Python 基础语法 | 10 |
| 条件、循环和函数 | 10 |
| DataFrame 建立与检查 | 10 |
| 选列、筛选、类型和缺失值 | 15 |
| 派生指标 | 10 |
| 分组聚合 | 15 |
| 占比和组内最大值 | 10 |
| 网页或 API 采集 | 10 |
| 导出和结果核验 | 5 |

#### 通过等级

- 90-100：可以独立完成真题，并开始提高代码健壮性。
- 80-89：达到本次暑期训练目标，可通过少量检查修正问题。
- 70-79：数据分析主线基本掌握，网页采集或分组统计仍需专项补强。
- 60-69：能跟随模板完成，但还不能独立迁移到新题。
- 60 以下：应回到具体薄弱周进行二次训练，不建议直接反复背整套答案。

### 下午复盘

每名学生完成个人能力表：

| 能力 | 独立 | 提示后 | 未完成 | 证据文件 |
|---|:---:|:---:|:---:|---|
| 独立创建和运行 `.py` |  |  |  |  |
| 判断数据类型 |  |  |  |  |
| 编写 `if/for/while` |  |  |  |  |
| 编写函数 |  |  |  |  |
| 创建和检查 DataFrame |  |  |  |  |
| 条件筛选和多值匹配 |  |  |  |  |
| 数值转换与缺失值处理 |  |  |  |  |
| 计算派生指标 |  |  |  |  |
| 分组和多指标聚合 |  |  |  |  |
| 计算分类占比 |  |  |  |  |
| 选择组内最大值 |  |  |  |  |
| GET/HTML 采集 |  |  |  |  |
| POST/JSON 采集 |  |  |  |  |
| 分页采集 |  |  |  |  |
| 导出 CSV/Excel |  |  |  |  |

### 最终提交包

```text
暑期Python最终成果/
├── 第01周_基础代码/
├── 第02周_流程控制与函数/
├── 第03周_pandas清洗/
├── 第04周_pandas统计/
├── 第05周_网页采集/
├── 第06周_三套真题/
├── 最终测评/
├── 错题本.md
└── 个人能力表.md
```

---

## 五、六周考点覆盖矩阵

| 真题考点 | 第 1 周 | 第 2 周 | 第 3 周 | 第 4 周 | 第 5 周 | 第 6 周 |
|---|:---:|:---:|:---:|:---:|:---:|:---:|
| 文件、解释器、运行 | 主学 | 复习 | 应用 | 应用 | 应用 | 测评 |
| 变量和基本类型 | 主学 | 应用 | 应用 | 应用 | 应用 | 测评 |
| 列表和字典 | 入门 | 主学 | 应用 | 应用 | JSON 应用 | 测评 |
| `if` 条件 | 预览 | 主学 | 筛选迁移 | 应用 | 异常判断 | 测评 |
| `for` 循环 | 预览 | 主学 | 应用 | 应用 | 多表/多店铺 | 测评 |
| `while` 分页 |  | 主学 |  |  | 网络应用 | 名仕实战 |
| 函数、参数、返回值 |  | 主学 | 应用 | 应用 | 请求函数 | 测评 |
| DataFrame |  |  | 主学 | 主学 | 网页转表 | 实战 |
| 选列、`.loc()`、`.isin()` |  |  | 主学 | 应用 | 应用 | 青娅实战 |
| 类型和缺失值 | 入门 | 应用 | 主学 | 应用 | 应用 | 实战 |
| `apply/lambda` |  | 函数铺垫 | 主学 | 聚合应用 |  | 实战 |
| `groupby/agg` |  |  | 入门 | 主学 | 应用 | 名仕/科图 |
| `value_counts()` |  |  |  | 主学 | 应用 | 科图实战 |
| 布尔均值 | 真假入门 | 条件应用 | 应用 | 主学 |  | 科图实战 |
| `idxmax()` |  |  |  | 主学 |  | 科图实战 |
| `round/fillna` | 显示入门 |  | 主学 | 应用 |  | 青娅实战 |
| CSV/Excel 导出 |  |  | 主学 | 主学 | 应用 | 实战 |
| GET/HTML |  |  |  |  | 主学 | 青娅/科图 |
| POST/JSON |  | 字典铺垫 | DataFrame 铺垫 |  | 主学 | 名仕实战 |
| 多店铺分页 |  | 循环模型 | 合并铺垫 | 汇总铺垫 | 主学 | 名仕实战 |

---

## 六、分层作业规则

为避免零基础学生因速度差异掉队，每天作业分三层。

### 保底任务

所有学生必须完成：

- 重新运行课堂代码。
- 改一组输入数据。
- 写一条错误记录。
- 完成当天出门测。

### 标准任务

达到正常进度的学生完成：

- 从空白文件重写核心代码。
- 完成一个新的业务场景。
- 导出并检查结果。

### 拓展任务

进度较快的学生选择完成：

- 增加异常处理。
- 把重复代码封装为函数。
- 使用更稳妥的 `pd.to_numeric()`。
- 处理空数据、并列最大值或重复数据。
- 比较参考写法和改进写法。

拓展任务不能代替保底和标准任务。速度快但基础步骤不稳定的学生，仍需先完成闭卷复现。

---

## 七、教师每周检查清单

### 环境与文件

- 学生是否知道自己正在运行哪个文件。
- VS Code 是否选择了正确解释器。
- 输出文件是否生成在预期文件夹。
- 文件名是否符合题目。

### 代码理解

- 学生能否逐行解释，而不是只说“这是老师给的”。
- 学生能否改变输入数据并预测结果。
- 学生能否指出当前变量的类型。
- 学生能否说明一行 DataFrame 代表什么。

### 独立性

- 是否不看答案重写过。
- 报错时是否先阅读最后一行。
- 是否会使用 `head()`、`columns`、`dtypes` 等证据定位问题。
- 是否能在一级提示后继续，而不是等待完整答案。

### 结果质量

- 业务公式是否正确。
- 分组粒度是否正确。
- 比例分母是否正确。
- 排序和小数规则是否正确。
- CSV/Excel 是否能正常打开。

---

## 八、每天错误记录模板

```markdown
# 日期：

## 今天的任务

## 我遇到的错误

- 报错最后一行：
- 出错文件：
- 出错行号：
- 当时变量或 DataFrame 的实际内容：

## 原因

## 我如何验证原因

## 修复方法

## 下次看到类似错误时先检查什么
```

错误本中至少覆盖以下类别：

- 中文符号和英文符号。
- 括号或引号不配对。
- 缩进错误。
- 变量名拼写错误。
- 类型转换错误。
- 列名不存在。
- 条件筛选为空。
- `KeyError`。
- `ModuleNotFoundError`。
- 网络超时或状态码错误。
- DataFrame 空列表合并错误。
- CSV 中文乱码。

---

## 九、学习结束时的最低能力标准

到 8 月 28 日，学生至少应能独立完成以下任务：

1. 创建、保存、运行和重新打开 Python 文件。
2. 使用终端检查 Python 与安装包。
3. 判断并转换常见数据类型。
4. 使用列表、字典、条件、循环和函数。
5. 根据业务语言写出计算公式。
6. 创建 DataFrame 并检查结构。
7. 选列、筛选、转换类型和处理缺失值。
8. 使用向量化或 `apply()` 创建新列。
9. 使用 `groupby()` 和 `agg()` 完成多指标汇总。
10. 使用 `value_counts(normalize=True)` 计算占比。
11. 使用布尔均值计算指定类别比例。
12. 使用 `idxmax()` 选择组内最大值对应的整行。
13. 使用 GET 请求和 BeautifulSoup/`read_html()` 采集 HTML 表格。
14. 使用 POST 请求和 `response.json()` 处理 API。
15. 使用 `for + while` 完成多店铺分页采集。
16. 正确导出 Excel 和带中文编码的 CSV。
17. 打开结果文件并按题干逐项核验。
18. 在没有完整答案的情况下，根据报错和数据检查结果修复程序。

---

## 十、计划实施中的调整规则

本计划有明确终点，但不要求所有学生每天完全同速。

### 可以按计划继续的条件

- 周五核心测评达到 80 分。
- 至少 80% 学生能独立完成本周最小任务。
- 学生能解释关键代码，而不是只会复制运行。

### 需要放慢一天的条件

- 超过 20% 学生仍不能独立运行文件。
- 多数学生不理解当前数据类型。
- 多数学生在没有示例时无法写出核心 3-5 行。
- 输出文件虽生成，但学生无法解释指标来源。

### 放慢时的处理方式

- 不删除后续核心内容。
- 将周一前 30 分钟用于补强。
- 把拓展任务取消，保留保底和标准任务。
- 使用更小的数据手工核对。
- 让学生闭卷重写，而不是再次跟抄。

最终目标不是“在 8 月 28 日前看完所有代码”，而是让学生能够独立完成一条真实的：

```text
读题
-> 获取数据
-> 检查数据
-> 清洗数据
-> 计算指标
-> 分组汇总
-> 导出结果
-> 验证文件
```

完整工作流。
