证书台账整理(Certificate Ledger Organizer)
适用场景
教师 / 工作室成员(非主持人)按《学科工作室与共同体的考核评估细则》整理证书原件、论文、课题过程性材料,输出一份符合考核清单要求的竖版 A4 Word 留档文档。
核心输出
一份 Word(.docx),结构如下:
- 封面 / 目录(01–12 编号)
- 按细则大项分节:日常工作 / 活动展示 / 名师在线 / 教学研究 / 教育论文 / 教学成绩 / 其它成绩
- 证书排版:竖版 A4,每页上下两张证书,证书标题(如 【01】精品课指导 / 第8点·主题展示活动|省级·三等奖(指导))与证书同一页,放不下则缩小证书
- 过程性材料:先 docx→PDF,再渲染成高清 PNG 插入(避免文字模糊)
工作流程
第一步:读取考核细则 PDF
用 pdfplumber 提取细则文本,识别七大项及评分点。典型结构(供参考,实际以细则为准):
| 大项 | 分值 | 评分点 |
|------|------|--------|
| 日常工作 | 30 | 第 1–7 点 |
| 活动展示 | 15 | 第 8–9 点 |
| 名师在线 | 10 | 第 10–11 点 |
| 教学研究 | 10 | 第 12–13 点 |
| 教育论文 | 10 | 第 14 点 |
| 教学成绩 | 15 | 第 15 点 |
| 其它成绩 | 20 | 第 16–17 点 |
第二步:证书重命名 + 归类
- 用
os.listdir()列出真实文件名(中文长文件名在 bashls下会显示为截断简名,必须用 Python 读取全名)。 - 证书重命名规则:
序号_名称_等级_年份_姓名.后缀,序号 01 起。 - 归类规则(关键结论,直接套用):
- 课题证书 → 课题类别(教学研究):如"课改先进个人"属校级课题证书,归校级一档。
- 获奖类证书 → 其它成绩(第 16–17 点):如精品课相关证书,放最后一类"其它成绩"。
- 纯展示课类 → 活动展示(第 8 点):如教研分享、专题讲座、示范课。
- 北师大平台比赛 → 视同省级奖。
第三步:图片方向修复
竖版证书颠倒了,用 Pillow 逆时针旋转 90°:
from PIL import Image
im = Image.open(path)
im = im.rotate(90, expand=True) # 视具体情况选 90 / -90
im.save(path)
第四步:生成 Word(python-docx)
- A4 竖版:页面 21×29.7cm。
- 每页上下两张证书:用表格或段落控制,证书图片 + 标题放同一段落/单元格。
- 证书放不下时缩小:
doc.add_picture(path, width=Cm(...))动态调宽。 - 字体:用
run.font.name+_element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')设中文字体。
第五步(关键):过程性材料高清插入
直接插 Word 会模糊,正确链路是 docx → PDF → PNG → 插入 Word:
- docx → PDF(无 LibreOffice 时用 Word COM):
import win32com.client
word = win32com.client.Dispatch('Word.Application')
word.Visible = False
word.DisplayAlerts = False
doc = word.Documents.Open(src, ReadOnly=True)
doc.SaveAs2(dst, FileFormat=17) # 17 = wdFormatPDF
doc.Close(False)
word.Quit()
> 前置条件:本机装有 Microsoft Word 且 pywin32 可用。若无 Word,改用 LibreOffice soffice --headless --convert-to pdf。
- PDF → 高清 PNG(PyMuPDF,200 dpi 标准 A4 = 1654×2339):
import fitz # pymupdf
doc = fitz.open(pdf_path)
for i, page in enumerate(doc):
pix = page.get_pixmap(dpi=200)
pix.save(f"pages/page_{i+1:02d}.png")
- 把 PNG 按顺序插入 Word 对应章节(如"附:校本课题过程性材料合订本")。
第六步(可选):证书统一宽度 13.8cm + 锁定纵横比
用户要求所有证书图片宽度统一 13.8cm、高度按原始像素比等比缩放时:
- 读取图片自然像素比(从 docx 内嵌图片直接取,不必回源文件):
from docx import Document
import io
from PIL import Image
doc = Document(path)
for sh in doc.inline_shapes:
blip = sh._inline.graphic.graphicData.pic.blipFill.blip
part = doc.part.related_parts[blip.embed]
nw, nh = Image.open(io.BytesIO(part.blob)).size # 自然像素
ratio = nw / nh
if ratio > 1.0: # 横版 = 证书
sh.width = Cm(13.8)
sh.height = Cm(13.8 / ratio) # 锁定纵横比
# 竖版插图(论文页/过程材料页)不动
> 经验:先用 sh.width.cm / sh.height.cm 遍历打印全部 inline_shapes 的比例,ratio > 1(横版)的才是证书,竖版 A4 插图页跳过。
-
改完尺寸必须检查"一页两张"是否被破坏:图片缩小后,表格默认行高可能大于图片实际高度,反而把第二张证书挤到下一页,产生孤页(标题在上一页、证书在下一页)。
-
孤页修复(OXML 精确控制)——对证书表逐行设置:
from docx.oxml.ns import qn
from docx.oxml import OxmlElement
# 定位证书表:表格文字以【开头(如"【01】精品课指导…")
cert_tables = [i for i, el in enumerate(body)
if el.tag.endswith('}tbl') and text_of(el).startswith('【')]
for tr in tbl.findall(qn('w:tr')):
trPr = tr.find(qn('w:trPr'))
if trPr is None:
trPr = OxmlElement('w:trPr'); tr.insert(0, trPr)
# ① 禁止行内跨页断开
if trPr.find(qn('w:cantSplit')) is None:
trPr.append(OxmlElement('w:cantSplit'))
# ② 精确行高 = 行内最高图片cy(cm) + 0.4cm 文字预留
# a:ext 的 cy 单位是 EMU,360000 EMU = 1cm;行高单位 twips,1cm = 567 twips
max_cy_cm = max(int(e.get('cy', 0)) / 360000
for tc in tr.findall(qn('w:tc'))
for e in tc.iter(qn('a:ext')) if e.get('cy'))
th = OxmlElement('w:trHeight')
th.set(qn('w:val'), str(int((max_cy_cm + 0.4) * 567)))
th.set(qn('w:hRule'), 'exact')
trPr.append(th)
# ③ 单元格内段落零间距 + 单倍行距
# w:spacing before=0 after=0 line=240 lineRule=auto
# ④ 标题字号压到 10pt(w:sz/w:szCs val=20,半磅单位)
易错点与规避
| 坑 | 规避方法 |
|---|---|
保存 Word 报 PermissionError [Errno 13] |
文件被 Word/预览占用,存在 ~$ 锁文件。先换新文件名保存;锁文件消失后再覆盖正式名 |
中文文件名在 bash 报 FileNotFoundError |
用 Python os.listdir() + 关键字过滤(如 '板书' in f)取真实全名 |
长中文文件名在 ls 显示为截断简名 |
同上,永远用 os.listdir() |
文件名含 & 无法用 bash glob |
在 Python 中 os.rename |
| docx→PDF 无工具 | docx2pdf 也依赖 COM;直接走 Word COM(见第五步)或 LibreOffice |
| Pillow 渲染文字成图模糊 | 不要用 Pillow 渲染文字;改用 Word COM→PDF→PyMuPDF 200dpi |
Word COM SaveAs2 报错/无输出 |
残留 WINWORD 进程作祟:Get-Process WINWORD \| Stop-Process -Force 后重开。SaveAs2 失败可降级 SaveAs,两者参数一致 |
| 批量改格式导致页数暴涨 | 只做精准修改:按文字特征(如表格以【开头)定位目标元素,绝不用"段落以某词开头"做全局匹配(会误伤论文/过程材料章节);改页边距等全局操作会连锁影响所有页 |
| OXML 修改后布局更乱 | 修改前务必备份;改完立即 Word COM 转 PDF + PyMuPDF 渲染抽查页面,页数/孤页异常就回滚重来 |
| 图片改小反而出现孤页 | 表格默认行高 > 图片新高度,第二张被挤到下页。用 trHeight exact + cantSplit 精确锁行高(见第六步) |
交付与收尾
- 最终交付:正式文件
.docx(可能 20–25 MB,含高清插图属正常)。 - 提醒用户清理中间产物:旧版
.docx、模糊图目录、过程 PDF 中间页。 - 建议用户重点检查"过程性材料合订本"章节是否清晰可读。
依赖
- Python 包:
python-docx、pdfplumber、pymupdf(fitz)、Pillow、pywin32(Windows 转 PDF 用) - 可选:本机 Microsoft Word(COM 转 PDF)或 LibreOffice