前言
因为一些项目原因,我需要提供解析docx内容功能。本来以为这是一件比较简单的工作,没想到在解析复选框选项上吃了亏,并且较长一段时间内通过各种渠道都没有真正解决这一问题,反而绕了远路。
终于,我在github python-docx模块的Issues中找到了重要的思路及线索,并最终通过后续努力,实现了【解析docx/word文件文字、图片、复选框】这一功能。
Feature: Read checkboxes in Word forms · Issue #224 · python-openxml/python-docx · GitHub
python-docx基础操作
# 安装python-docx模块
pip install python-docx
import os
import docx
import time# 图片附件的存储地址
image_save_path = 'appendix_dir'# 读取docx表格里的数据,图片及文字
def read_table_from_docx(file_path):""":param file_path::return: table_data, images"""# 读取docx/word文件doc = docx.Document(file_path)# 获取docx中的table对象tables = doc.tablestable_data = []images = []# 拿取文件中的图片对象,并存储在images列表里for rel in doc.part.rels.values():if "image" in rel.reltype:image = rel.target_partimage_data = image.blobimages.append(image_data)# 读取文件表格中的文字内容# 这里不能解析特殊字符和复选框# 并且合并单元格的文字内容,将出现多行多列重复出现,需要注意for table in tables:for row in table.rows:row_data = []for cell in row.cells:# print(cell, cell.text)row_data.append(cell.text)table_data.append(row_data)return table_data, imagestable_data, images = read_table_from_docx('template.docx')
print(table_data)# 另存docx图片到本地
for i, image_data in enumerate(images):# 拼接 存储图片 绝对路径image_name = f"expert_{int(time.time() * 1000)}.jpg"with open(os.path.join(image_save_path, image_name), "wb") as f:f.write(image_data)
拿取复选框选项
关于docx复选框,在这次项目中遇到了一种独特的复选框样式,这种样式并不是通过wps里的【复选框内容控件】创建的,让我一时没办法找到方向。
这是正常用wps添加的复选框方式
很明显,和我的目标不太一样
二者都没办法通过【python-docx基础操作】拿到,因此我只能继续刨坑,终于如【前言】所述,我不得已去模块github的评论区里找到了线索——直接以xml的形式剖析docx文件,并获取复选框选项。
这里为了节约文本资源(太懒了),直接上代码吧!
from docx import Documentdocument = Document('template1.docx')
tables = document.tables
content = []
for table in tables:for row in table.rows:for cell in row.cells:for paragraph in cell.paragraphs:p = paragraph._element# 打印docx的xml内容形式# print(p.xml)# 拿取所有<w14:checkbox>标签的匹配xml数据checkBoxes = p.xpath('.//w14:checkbox')if checkBoxes:# 解析<w14:checkbox>内部的内容for checkBox in checkBoxes:# 尝试匹配xml中的<w14:val>对象,也就是上面wps自建的复选框checked_state = checkBox.xpath('.//w14:checked/@w14:val', namespaces={'w14':'http://schemas.microsoft.com/office/word/2010/wordml'})if checked_state:checked_value = checked_state[0] # 获取第一个匹配的属性值print(paragraph.text, "Checked value:", checked_value)break# 这是原模板的复选框选项拿取方案# checkBoxes = p.xpath('.//w:r')# if checkBoxes:# for checkBox in checkBoxes:# checked_state = checkBox.xpath('.//w:sym/@w:char')# if checked_state:# checked_value = checked_state[0] # 获取第一个匹配的属性值# print(paragraph.text, "Checked value:", checked_value)# break
这是我的结果【1是选择,0是未选择】
这是docx解析后的xml内容,请自行体会代码与它的联系吧
<w:p xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:wpsCustomData="http://www.wps.cn/officeDocument/2013/wpsCustomData"><w:pPr><w:jc w:val="both"/><w:rPr><w:rFonts w:hint="eastAsia" w:ascii="仿宋_GB2312" w:hAnsi="仿宋_GB2312" w:eastAsia="仿宋_GB2312" w:cs="仿宋_GB2312"/><w:u w:val="single"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:hint="default" w:ascii="仿宋_GB2312" w:hAnsi="仿宋_GB2312" w:eastAsia="仿宋_GB2312" w:cs="仿宋_GB2312"/><w:sz w:val="21"/><w:szCs w:val="21"/></w:rPr><w:sym w:font="Wingdings" w:char="00A8"/></w:r><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:ascii="仿宋_GB2312" w:hAnsi="仿宋_GB2312" w:eastAsia="仿宋_GB2312" w:cs="仿宋_GB2312"/><w:sz w:val="21"/><w:szCs w:val="21"/><w:lang w:val="en-US" w:eastAsia="zh-CN"/></w:rPr><w:t>这是选项一</w:t></w:r><w:bookmarkStart w:id="0" w:name="_GoBack"/><w:bookmarkEnd w:id="0"/><w:sdt><w:sdtPr><w:rPr><w:rFonts w:hint="eastAsia" w:ascii="仿宋_GB2312" w:hAnsi="仿宋_GB2312" w:eastAsia="仿宋_GB2312" w:cs="仿宋_GB2312"/><w:color w:val="auto"/><w:kern w:val="2"/><w:sz w:val="21"/><w:szCs w:val="24"/><w:lang w:val="en-US" w:eastAsia="zh-CN" w:bidi="ar-SA"/></w:rPr><w:id w:val="147457823"/><w14:checkbox><w14:checked w14:val="1"/><w14:checkedState w14:val="2612" w14:font="MS Gothic"/><w14:uncheckedState w14:val="2610" w14:font="MS Gothic"/></w14:checkbox></w:sdtPr><w:sdtEndPr><w:rPr><w:rFonts w:hint="eastAsia" w:ascii="仿宋_GB2312" w:hAnsi="仿宋_GB2312" w:eastAsia="仿宋_GB2312" w:cs="仿宋_GB2312"/><w:color w:val="auto"/><w:kern w:val="2"/><w:sz w:val="21"/><w:szCs w:val="24"/><w:lang w:val="en-US" w:eastAsia="zh-CN" w:bidi="ar-SA"/></w:rPr></w:sdtEndPr><w:sdtContent><w:r><w:rPr><w:rFonts w:ascii="MS Gothic" w:hAnsi="MS Gothic" w:eastAsia="宋体" w:cs="Times New Roman"/><w:color w:val="auto"/><w:kern w:val="2"/><w:sz w:val="21"/><w:szCs w:val="24"/><w:lang w:val="en-US" w:eastAsia="zh-CN" w:bidi="ar-SA"/></w:rPr><w:t>☒</w:t></w:r></w:sdtContent></w:sdt><w:r><w:rPr><w:rFonts w:hint="eastAsia" w:ascii="仿宋_GB2312" w:hAnsi="仿宋_GB2312" w:eastAsia="仿宋_GB2312" w:cs="仿宋_GB2312"/><w:i w:val="0"/><w:iCs w:val="0"/><w:color w:val="000000"/><w:kern w:val="0"/><w:sz w:val="21"/><w:szCs w:val="21"/><w:u w:val="none"/><w:bdr w:val="single" w:color="000000" w:sz="4" w:space="0"/><w:lang w:val="en-US" w:eastAsia="zh-CN" w:bidi="ar"/></w:rPr><w:drawing><wp:anchor distT="0" distB="0" distL="114300" distR="114300" simplePos="0" relativeHeight="251659264" behindDoc="0" locked="0" layoutInCell="1" allowOverlap="1"><wp:simplePos x="0" y="0"/><wp:positionH relativeFrom="column"><wp:posOffset>0</wp:posOffset></wp:positionH><wp:positionV relativeFrom="paragraph"><wp:posOffset>0</wp:posOffset></wp:positionV><wp:extent cx="18415" cy="19685"/><wp:effectExtent l="0" t="0" r="0" b="0"/><wp:wrapNone/><wp:docPr id="1" name="图片_2"/><wp:cNvGraphicFramePr/><a:graphic xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:nvPicPr><pic:cNvPr id="1" name="图片_2"/><pic:cNvPicPr/></pic:nvPicPr><pic:blipFill><a:blip r:embed="rId4"/><a:stretch><a:fillRect/></a:stretch></pic:blipFill><pic:spPr><a:xfrm><a:off x="0" y="0"/><a:ext cx="18415" cy="19685"/></a:xfrm><a:prstGeom prst="rect"><a:avLst/></a:prstGeom><a:noFill/><a:ln><a:noFill/></a:ln></pic:spPr></pic:pic></a:graphicData></a:graphic></wp:anchor></w:drawing></w:r>
</w:p>