16.3.docx
Windows 10
Python 3.7.7 @ MSC v.1916 64 bit (AMD64)
Latest build date 2020.09.21
python-docx version: 0.8.10
python-docx
是Python操作word文档时最常用的库。python-docx
可以创建一个word文档,往文档中添加文字、表格、图片,并且可以设置样式;也可以从一个word文档中读取文字、表格、内联的图片。
python-docx
具有以下特点:
python-docx
虽然可以设置样式,但它的样式设置不能包含word的所有样式。- Word有样式管理器,
python-docx
可以操作这个管理器,添加自定义的样式到管理器中,或者从管理器选取一个样式加以应用。 python-docx
只能读取内联图片。
如果对docx文档的样式设置有较高要求,可以先设置好一个word模板文档,然后用python-docx
读入该模板文档,操纵该文档的样式管理器。如果不能用Word自定义样式,又对样式设置有很高要求,只能考虑VBA、win32api等功能齐全的工具了。
读取docx
from docx import Document
读取文本
# 打开 SQL笔记.docx 文档
doc_path = r"datasets/file/SQL笔记.docx"
doc = Document(doc_path)
# 读取每段的文本
pl = [paragraph.text for paragraph in doc.paragraphs]
print(f"一共有 {len(pl)} 个paragraph")
print(pl[100])
一共有 835 个paragraph
1986 年,ANSI 首次制定了 SQL 的标准。修订后的标准以修订年份来命名,例如 SQL:1999、SQL:2003、SQL:2008
等。
读取表格
# 读取所有表格
tables = doc.tables
# 打印第一个表格的内容
for row in tables[0].rows:
for cell in row.cells:
print(cell.text, end=' \t | \t')
print()
含义 | 运算符 |
加法运算 | + |
减法运算 | - |
乘法运算 | * |
除法运算 | / |
读取样式
# 获取该文档的所有样式
styles = list(doc.styles)
# 获取第一个样式的名字
print(styles[0].name)
# 获取第一个样式的字体
print(styles[0].font.name)
# 获取第一个样式的字体的大小
print(styles[0].font.size)
Normal
Times New Roman
139700
读取内联图片
python-docx
读取内联图片的方式有点复杂,官方文档好像也没有提及如何提取图片。实际上docx文档是包含了一些xml文件和二进制文件的zip压缩文档。所以,可以通过分析xml的标签或者将doc解压缩来获取图片的信息。实际上,python-docx
正是通过解析docx文档中的xml文件来提取其中的信息。
document.xml 文件包含了docx文件的主要内容,图片的信息也在其中。在 document.xml 中,图片的出现顺序和图片在文件中显示的顺序是一致的。每个图片都有一个r:id
的标签?可以迭代Document
的inline_shapes
对象,从而获得其中的每一个inline_shape
对象的riD
值。
rId = []
for inline_img in doc.inline_shapes:
# pic.blipFill.blip.embed 这些都是 document.xml 中的标签
blip = inline_img._inline.graphic.graphicData.pic.blipFill.blip
rId.append(blip.embed)
print(rId)
['rId19', 'rId20', 'rId24', 'rId25', 'rId27', 'rId28']
通过 Document.part
属性,可以获取储存了document.xml
解析结果的DocumentPart
对象
document_part = doc.part
print(document_part.partname)
/word/document.xml
DocumentPart
对象的属性related_parts
是一个字典,将document.xml
中的每一个r:id
映射到该r:id
所在的部分。因此,可以通过内联图片的r:id
从属性related_parts
中获取图片的xml原始信息。
rid = rId[0]
image_part = document_part.related_parts[rid]
print(f"'{rid}'对应的图片文件名:", image_part.filename)
'rId19'对应的图片文件名: image.png
然而,通过.filename
属性获得的文件名似乎不是完全正确的,完整的图片文件名还带有编号的。通过.partname
属性,可以看到图片在docx压缩文件中的真实文件名。
print(f"'{rid}'对应的图片文件名:", image_part.partname)
'rId19'对应的图片文件名: /word/media/image1.png
通过.blob
属性(blob在计算机领域中,似乎是binary large object的缩写),可以获得图片的二进制数据。
print(type(image_part.blob))
print(len(image_part.blob))
<class 'bytes'>
23329
保存图片的二进制数据,可以得到图片文件
with open(r"datasets/file/image1.png", "wb") as f:
f.write(image_part.blob)
os.remove(r"datasets/file/image1.png")
或者使用cv2
库将二进制的图片数据转换为数组,通过matplotlib可以显示出该图片。
import matplotlib.pyplot as plt
import cv2
import numpy as np
img = cv2.imdecode(np.frombuffer(image_part.blob, np.uint8), cv2.IMREAD_COLOR)
plt.imshow(img)
InlineShape
对象还带有图片的长宽信息(但好像不太准):
print(inline_img.height.cm, inline_img.width.cm)
1.7796 10.591322222222223
InlineShape
对象还带有一个name
标签,但不知道是什么含义:
print(inline_img._inline.graphic.graphicData.pic.nvPicPr.cNvPr.name)
Picture 237