# 上海中考招生计划与成绩导入说明 本文档记录本项目每年从 PDF/图片整理上海中考招生计划、成绩,并导入 MySQL 表 `kylx365_db.MPS_Score` 的需求、步骤和注意事项。 当前已完成 2026 年“计划”中的 1、2、3:自主招生、名额到区、名额到校。 ## 年度工作范围 每年需要处理两大类数据。 一、计划 1. 自主招生 2. 名额到区 3. 名额到校 4. 1-15 志愿 二、成绩 1. 自主招生 2. 名额到区 3. 名额到校 4. 1-15 志愿 2026 年当前状态: - 计划/自主招生:已导入 - 计划/名额到区:已导入 - 计划/名额到校:已导入 - 计划/1-15 志愿:待官方文件发布后导入 - 成绩四类:预计 7 月中旬后导入 ## 数据库与核心表 目标数据库:`kylx365_db` 核心表: - `MPS_School`:学校表,所有学校相关信息以此表为准。 - `MPS_Score`:计划与成绩表,所有导入结果写入此表。 常用参照查询: ```sql SELECT * FROM kylx365_db.MPS_School WHERE SchoolType1 = '高中'; ``` ```sql SELECT * FROM kylx365_db.MPS_Score WHERE ScoreYear = '2025' AND ScoreType = '名额到校' AND DistrictID = 1; ``` 数据库连接信息不要写入 README 或提交到仓库。当前脚本里使用本机已有配置和 PyMySQL 驱动连接,后续最好抽成单独的本地配置文件或环境变量。 ## DistrictID 对照 ```text 1 黄浦区 2 徐汇区 3 长宁区 4 静安区 5 普陀区 6 虹口区 7 杨浦区 8 闵行区 9 宝山区 10 嘉定区 11 浦东新区 12 金山区 13 松江区 14 青浦区 15 奉贤区 16 崇明区 ``` ## MPS_Score 写入规则 计划类导入一般只写计划数,不写成绩。 通用字段规则: - `ScoreYear`:年份,例如 `2026` - `ScoreType`:`自主招生`、`名额到区`、`名额到校`、`1-15志愿` - `DistrictID`:对应区 ID - `SchoolTarget`:高中学校 `MPS_School.ID`,以字符串写入 - `SchoolFullName`:必须使用高中 ID 对应的 `MPS_School.SchoolFullName` - `PlanNum`:计划人数 - `ScoreTotal`、`Score1`、`Score2`、`Score3`、`Score4`:计划导入时填 `0` - `ScoreTotalDifferenceValue`:计划导入时填 `0` - `PlanNumDifferenceValue`:当前计划数减去上一年同维度计划数 - `OrderID`:当前计划导入填 `0` - `SchoolNumber`、`SchoolNumber2`:当前计划导入填空字符串 - `SchoolOfGraduation1`:当前计划导入填 `"0"` 名额到校额外规则: - `SchoolOfGraduation`:初中学校 `MPS_School.ID` - `SchoolFullNameJunior`:必须使用初中 ID 对应的 `MPS_School.SchoolFullName` - 一条数据的唯一业务维度可按 `ScoreYear + ScoreType + DistrictID + SchoolOfGraduation + SchoolTarget` 理解。 - 不能用 PDF 里的简称直接写入 `SchoolFullNameJunior` 或 `SchoolFullName`。 自主招生额外规则: - 普通自主招生拆成: - `1学科` - `2体育` - `3艺术` - 国际课程班/中外合作办学拆成: - `4国际(本市)` - `5国际(非本市)` - `SchoolTargetRemark2` 可参考上一年同学校同类别备注;体育/艺术通常沿用“市级优秀体育学生”“市级艺术骨干学生”等说明。 名额到区额外规则: - `SchoolOfGraduation = 0` - `SchoolFullNameJunior = NULL` - `SchoolTargetRemark = ""` - 维度是“区 + 高中”。 ## 总体操作流程 每一类数据都按以下流程做: 1. 先研究上一年 PDF 与上一年数据库数据,确认字段含义和写入形态。 2. 读取新一年 PDF/图片,优先用表格解析;表格解析失败或 PDF 其实是图片时再 OCR/人工读图。 3. 先匹配学校,不确定的数据不要导入,写入问题清单。 4. 先 dry-run 或打印 ready 汇总,核对每区行数和计划数。 5. 只插入新数据,不删除、不修改已有数据。 6. 导入后查询 `MPS_Score` 总行数、总计划数、分区汇总。 7. 对问题学校更新 `MPS_School` 后,再运行补录脚本,只补缺失行,并刷新问题清单。 重要原则: - 凡是弄不清楚的,先不入库,放入 JSON 问题清单。 - 若某个区解析问题较多,整个区可以先不动,等其他区处理完再单独解决。 - 每次补录必须跳过已存在业务 key,避免重复插入。 - 新增/改名学校优先修正 `MPS_School`,再重新匹配导入。 ## PDF/图片解析经验 优先级: 1. 有 6 位学校编号:优先用编号匹配。 2. 有学校全称:用 `SchoolFullName` 匹配。 3. 有简称或别名:用 `SchoolShortName`、`SchoolOtherName` 匹配。 4. 仍不能唯一匹配:列为问题数据。 学校名称常见问题: - PDF 中会使用简称,而且初中简称比高中多。 - 有学校改名,PDF 可能写成“原名(现新名/校区)”。 - 有新增学校,学校表中原本没有。 - OCR 可能把换行、空格、序号、备注混进学校名。 - 部分 PDF 表格中的学校名可能被拆成多行,需要清理换行再匹配。 本次经验: - 高中通常有 6 位编号,匹配相对稳定。 - 名额到校的初中数量多,名称最容易出问题。 - `SchoolOtherName` 很适合放改名后的现名或曾用名。 - 对“原名(现某某)”这种文本,匹配时应同时尝试原名、括号内现名、去括号名称。 - 图片清晰时可以 OCR/读图解决,但要把结果转成结构化行,再按学校表 ID 入库。 ## 当前脚本说明 脚本分为三类:主流程脚本、公共解析/补录脚本、2026 一次性补充脚本。后续年度工作时,主流程和公共脚本可以复制改年份;一次性补充脚本主要用于追溯 2026 的特殊处理,不建议直接运行到新年份。 自主招生: - `import_mps_score_2026.py` - 读取 2026 自主招生计划 PDF 与国际课程班/中外合作办学 PDF。 - 导入 `ScoreType = '自主招生'`。 - 脚本会在已有 2026 自主招生数据时拒绝再次插入。 名额到区: - `import_mps_score_quota_2026.py` - 读取 16 个区的名额到区 PDF。 - 支持 `--dry-run`。 - 如果某区已存在数据,会跳过并报告。 - 对图片或解析失败区,使用 `import_mps_score_quota_manual_2026.py` 做手工/OCR 补充。 名额到校: - `research_mps_score_school_quota_2026.py` - 负责学校加载、名称清洗、PDF 表格解析、学校匹配。 - 已支持编号匹配、全称/简称/别名匹配、括号内“现名”匹配、同区唯一包含式匹配。 - `import_mps_score_school_quota_2026.py` - 主导入脚本,读取 16 个区名额到校 PDF。 - 支持 `--dry-run`。 - 解析不确定的数据写入 `mps_score_school_quota_2026_problems.json`。 - `import_mps_score_school_quota_supplement_2026.py` - 用于补充处理徐汇、嘉定等表格/OCR特殊区。 - `import_mps_score_school_quota_hongkou_2026.py` - 用于处理虹口图片读图后的结构化数据。 - `fix_mps_score_school_quota_problems_2026.py` - 当 `MPS_School` 中新增/修正学校后,重新解析问题区并补插当前能匹配的数据。 - 会跳过数据库中已存在的 `DistrictID + SchoolOfGraduation + SchoolTarget` 组合。 - 会刷新 `mps_score_school_quota_2026_problems.json`,只保留仍未解决的问题。 2026 一次性补充脚本: - `import_mps_score_quota_manual_2026.py`:用于 2026 名额到区图片/OCR特殊区的手工补录,不是新年份通用入口。 - `import_mps_score_school_quota_hongkou_2026.py`:用于 2026 虹口名额到校图片读图后的手工矩阵导入,不是新年份通用入口。 - `import_mps_score_school_quota_supplement_2026.py`:包含 2026 徐汇手工矩阵和嘉定特殊 PDF 解析;其中 `collect_jiading` 目前仍被 `fix_mps_score_school_quota_problems_2026.py` 引用,所以不要单独删除。 生成物: - `__pycache__/` 和 `*.pyc` 是 Python 运行缓存,不属于业务数据或脚本,已在主仓库 `.gitignore` 中忽略。 ## 2026 已完成结果 计划/自主招生: - `ScoreYear = 2026` - `ScoreType = 自主招生` - 已导入 265 行 - 计划数合计 7813 计划/名额到区: - `ScoreYear = 2026` - `ScoreType = 名额到区` - 已导入 947 行 - 计划数合计 7171 计划/名额到校: - `ScoreYear = 2026` - `ScoreType = 名额到校` - 已导入 3892 行 - 计划数合计 12833 - 问题清单 `mps_score_school_quota_2026_problems.json` 已清空 2026 名额到校最终分区汇总: | DistrictID | 区 | 行数 | 计划数 | | --- | --- | ---: | ---: | | 1 | 黄浦区 | 217 | 996 | | 2 | 徐汇区 | 221 | 899 | | 3 | 长宁区 | 63 | 418 | | 4 | 静安区 | 271 | 1102 | | 5 | 普陀区 | 179 | 736 | | 6 | 虹口区 | 80 | 488 | | 7 | 杨浦区 | 144 | 707 | | 8 | 闵行区 | 460 | 1290 | | 9 | 宝山区 | 348 | 1076 | | 10 | 嘉定区 | 130 | 612 | | 11 | 浦东新区 | 1259 | 2082 | | 12 | 金山区 | 56 | 355 | | 13 | 松江区 | 190 | 779 | | 14 | 青浦区 | 93 | 725 | | 15 | 奉贤区 | 131 | 345 | | 16 | 崇明区 | 50 | 223 | ## 常用核验 SQL 总量: ```sql SELECT COUNT(*) AS c, SUM(PlanNum) AS total FROM MPS_Score WHERE ScoreYear = '2026' AND ScoreType = '名额到校'; ``` 分区: ```sql SELECT DistrictID, COUNT(*) AS c, SUM(PlanNum) AS total FROM MPS_Score WHERE ScoreYear = '2026' AND ScoreType = '名额到校' GROUP BY DistrictID ORDER BY DistrictID; ``` 检查某区上一年参照: ```sql SELECT * FROM MPS_Score WHERE ScoreYear = '2025' AND ScoreType = '名额到校' AND DistrictID = 1 ORDER BY ID; ``` 查初中学校名称: ```sql SELECT ID, DistrictID, SchoolNumber, SchoolFullName, SchoolShortName, SchoolOtherName FROM MPS_School WHERE SchoolType1 = '初中' AND ( SchoolFullName LIKE '%学校名关键词%' OR SchoolShortName LIKE '%学校名关键词%' OR SchoolOtherName LIKE '%学校名关键词%' ); ``` ## 明年复制脚本时要改的地方 把脚本从 2026 复制到新年份后,至少检查这些常量: - `YEAR` - `PREVIOUS_YEAR` - `BASE_DIR` - PDF 文件名 - 问题 JSON 文件名 - 特殊区手工数据脚本中的高中代码、初中代码、计划矩阵 - 自主招生中国际课程班 PDF 名称 导入前必须确认目标年份目标类型没有已有数据,或脚本明确支持跳过/补录。 不要为了重新跑脚本而删除数据库旧数据,除非明确确认要重做且已备份。 ## 待办 计划/1-15 志愿: - 等 2026 官方文件发布后处理。 - 需要先研究 2025 的 PDF 与数据库写入形态,再决定 `ScoreType`、字段、维度和差值计算。 成绩导入: - 预计 7 月中旬后开始。 - 四类成绩都要先研究上一年数据。 - 成绩类导入会涉及 `ScoreTotal`、`Score1`、`Score2`、`Score3`、`Score4` 等字段,不能沿用计划类全部填 0 的规则。 - 成绩导入前要明确每个分数列的含义、缺考/无分/未录取的表示方式,以及是否需要计算差值。