根据简历自动填写 DOCX 表单。核心原则:不删字段,缺失留白。
支持两种格式,自动识别:
pdfplumber 提取全文字符串
zipfile + 正则提取 文本
# 简历文本提取
import pdfplumber
with pdfplumber.open("简历.pdf") as pdf:
resume_text = "\n".join(p.extract_text() for p in pdf.pages)
用正则规则从简历文本中提取关键字段,存入 dict:
| 字段 | 匹配规则 |
|------|---------|
| 姓名 | 首行或"姓名:"后第一个词 |
| 性别 | "男"/"女",或 男/YYYY 格式 |
| 出生年月 | YYYY.MM / YYYY年MM月 等 |
| 民族 | "民族:"后内容 |
| 政治面貌 | "政治面貌:"后内容,或"党派/群众"类格式 | 党员/群众/团员 |
| 健康状况 | 含"健康"字样的行 |
| 参加工作时间 | "参加工作"或首段年份 |
| 手机号码 | 11位手机号正则 |
| 电子邮箱 | 标准邮箱正则 |
| 教育经历 | 时间+院校+专业+学历(最多3段) |
| 工作经历 | 时间段+公司名+岗位(全部段落,按时间倒序) |
| 技术职称 | 如"中级经济师" |
| 职业资格 | 证券/基金/CPA/CFA 等 |
| 英语等级 | CET-4/CET-6 |
| 特长 | Wind/Excel/Python 等工具关键词 |
> 重要规则:简历中未出现的字段(如籍贯、身份证号、推荐人等),一律留空白,不推断、不猜测。
在填写前,必须主动询问以下问题:
如果简历有多段工作经历,而表单模板只有 1 个工作经历区块,必须询问用户填写哪一段:
发现简历中有 N 段工作经历:
1. [公司名A] [时间]
2. [公司名B] [时间]
3. [公司名C] [时间]
请告诉我要填哪一段(填序号,如"2")
如果表单有多个工作经历区块(如 3 行),则按时间倒序填入前 3 段,不足则留空。
如果简历中提取到了工作职责和业绩数据,自动填入对应字段,无需询问。
使用 docx skill 的 unpack.py 脚本:
python <docx_unpack_path> <模板.docx> <解包目录> --overwrite
通过字符串替换在空白单元格中插入 元素:
def fill_field(content, label, value):
"""
找到 <w:t>label</w:t> 标签,
在其后紧邻的空白单元格中插入:
<w:r><w:rPr>...</w:rPr><w:t>value</w:t></w:r>
"""
# 1. 定位 label 标签
label_tag = f'<w:t>{label}</w:t>'
pos = content.find(label_tag)
# 2. 找该单元格末尾和下一个值单元格
tc_end = content.find('</w:tc>', pos)
val_tc = content.find('<w:tc>', tc_end)
# 3. 在 </w:pPr> 后插入 run
...
格式要求:字体 仿宋_GB2312,颜色 000000,无字间距调整。
教育经历通常是合并单元格表格,结构为:
[教育经历 vMerge] | [起止时间] | [毕业院校] | [系及专业] | [学历学位]
| (行1) | (行1) | (行1) | (行1)
| (行2) | (行2) | (行2) | (行2)
| (行3) | (行3) | (行3) | (行3)
遍历每一行数据,按列填入对应单元格。
通过 工作单位 标签定位,找到紧邻的值单元格后依次填入:
工作单位 → 起止时间(取第二个"起止时间")→ 岗位 → 工作职责 → 相关业绩
python <docx_pack_path> <解包目录> <输出.docx> --original <模板.docx>
输出文件名规范:{原名-填表人-填表岗位}.docx
| 表单字段 | 简历匹配关键词 | 备选 |
|---------|------------|------|
| 姓名 | 首行、姓名: | - |
| 性别 | 男/女 | 简历中含"男/"或"女/" |
| 出生年月 | 出生年月:/YYYY.MM | 首行数字 |
| 民族 | 民族: | 常见民族名称(如汉族) |
| 政治面貌 | 政治面貌: | 党员/群众/团员 |
| 健康状况 | 健康 | 良好/一般 |
| 参加工作时间 | 参加工作: | 首段年份 |
| 手机号码 | 手机:/1开头11位 | 直接手机号 |
| 电子邮箱 | 邮箱:/@ | - |
| 技术职称 | 中级经济师/CPA/CFA | 证书栏 |
| 职业资格 | 从业资格 | 证券/基金/本币 |
| 英语等级 | CET/英语四六级 | - |
| 特长 | 工具栏 | Wind/Excel/Python |
| 工作单位 | 公司名 | 含"证券/信托/银行/评级" |
| 起止时间 | 格式如 YYYY/M—YYYY/M 或 YYYY年M月—至今 | - |
| 岗位 | 经理/研究员/分析师 | - |
| 工作职责 | 工作职责:⚫ | (1)(2)(3)列表 |
| 相关业绩 | 工作成果:⚫ | 数字+排名 |
直接留空,不做任何推断。这是最重要的一条原则。
例外:如果简历提供了原始 PDF,AI 可以看到格式化的段落文字(如用"⚫"或"●"列举的职责),直接复制对应内容填入。
[SKIP]
zipfile.ZipFile 打包
起止时间/毕业院校/系及专业/学历学位 是数据行,不是表头行;表头行的标签文字在 中,不要混淆
起止时间 有两个(一个在教育表头,一个在工作表头),定位时必须找第二个才能正确填入工作经历区块
w:vMerge),跳过合并格的第一个值(实际显示的是合并源)
--original 参数,否则样式丢失
标签可能带属性(如 ),匹配时用 re.search(r']*>')
MergedCell 对象,直接赋值会报 AttributeError: 'MergedCell' object attribute 'value' is read-only。必须先遍历 ws.merged_cells.ranges 确认每个字段合并区域的 min_row/min_col,只向左上角坐标写入。建议在填写前专门写一个 inspect 脚本打印所有关键行的合并结构,再据此硬编码坐标。
共 4 个版本