每到新生开学季,对班主任老师来说,最头疼的事情莫过于整理新生的学籍档案。小老老师最近就遇到了一个这样的问题:手上有一个Word文档,里面保存学生的学籍信息,一页一个表格,每个表格是学生的学籍卡电子版,其中包含学生的身份证和学生照片。他的需求是要把表格中的照片保存到指定文件夹,结果要以学生的身份证号码命名。小李老师的困惑是,这样的表格有400个之多,如果手动把几百个表格中的照片一张一张另存为,再一个一个复制身份证号码,再重命名,恐怕没有几个小时是干不完的,而且还很容易出错。一旦出现错误再去核对、修改,又得好长时间。今天就以小李老师的这个问题为例,就教大家如何用Python来解决这个问题。解决问题的代码只有28行代码,即便更多的表格也能瞬间完成。三是提取图片并以指定方式重命名。下面是完成完整代码:from docx import Documentfrom pathlib import Pathdocx_path = Path(r"E:\学生学籍卡六年级.docx")save_dir = Path(r"E:\六年级以身份证命名照片")row,col = 3,3 # 身份证所在单元格坐标,索引从0开始row_img,col_img = 1,6 # 照片所在单元格坐标,索引从0开始save_dir.mkdir(parents=True,exist_ok=True) # 新建文件夹doc = Document(docx_path) # 读取文档embed_key = "{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed"def save_img(rid, save_name): part = doc.part.related_parts[rid] suffix = part.content_type.split("/")[-1] file_path = save_dir / f"{save_name}.{suffix}" file_path.write_bytes(part.blob)for table in doc.tables: used_rids = set() name = table.cell(row, col).text.strip() # 身份证 img_cell = table.cell(row_img, col_img) # 照片所在单元格 for para in img_cell.paragraphs: for run in para.runs: for blip in run.element.xpath(".//a:blip"): rid = blip.get(embed_key) if rid not in used_rids: used_rids.add(rid) save_img(rid, name)
这段代码只有28行,理解了这几个硬核知识点,所有的难题都会迎刃而解。其实不难发现,在python-docx模块中,没有直接获取图片的方法。docx格式的文档其本质是一个压缩包,图片作为其中一个部件保存在这个压缩包中,我们需要用特定的方法来抓取图片。embed_key = "{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed"
这句代码是OpenXML中定义的命名空间。docx文档中的图片是通过<a:blip>标签引用的,而真正的图片数据存储在r:embed属性所指向的ID中。http://schemas.openxmlformats.org/officeDocument/2006/relationships是文件规定的关联地址。embed是存放图片资源的ID。for blip in run.element.xpath(".//a:blip"):
代码中使用了run.element.xpath(".//a:blip"),普通的遍历只能看到文字,看不到图像,使用xpath可以直接穿透到文件的底层,精准定位到所有图片的节点(就是blip),从而拿到它们的embed。如果你再遇到几百份,甚至更多的学籍卡、员工档案等需要批量整理照片,这段代码只要对第3-6行稍做修改,就可以直接使用使用,再也不用一个一个手动复制粘贴了。如果你觉得有用,欢迎点赞、收藏,并转发给需要的同事吧!