使用 Python-docx
模块可以自动化的解决大部分操作。Python-docx
是一个很强大的包,
可以用来读取和创建 DOCX 文档,
包含段落、分页符、表格、图片、标题、样式等几乎所有的word文档中能常用的功能。
首先安装 Python-docx
模块,通过 pip
命令:
pip install python-docx
Requirement already satisfied: python-docx in /opt/conda/lib/python3.12/site-packages (1.1.2) Requirement already satisfied: lxml>=3.1.0 in /opt/conda/lib/python3.12/site-packages (from python-docx) (5.3.1) Requirement already satisfied: typing_extensions>=4.9.0 in /opt/conda/lib/python3.12/site-packages (from python-docx) (4.12.2) Note: you may need to restart the kernel to use updated packages.
安装完成后测试一下是否安装成功。
import docx
DOCX 文档的内容有段落、表格等。 这一节先打开示例文件, 看一下能够解析出来哪些内容。
from docx import Document
dfile = Document('/data/demo/demo.docx')
core_properties = dfile.core_properties
for idx, uu in enumerate(dir(core_properties)[27:]):
print(idx, uu)
0 _element 1 author 2 category 3 comments 4 content_status 5 created 6 identifier 7 keywords 8 language 9 last_modified_by 10 last_printed 11 modified 12 revision 13 subject 14 title 15 version
上面列出的即为 DOCX 文档元数据属性项支持的 15 个属性。
所有unicode
值限制为255个字符(非字节)。
author(unicode)
注意:在规范中名为“ creator”。主要负责制作资源内容的实体。category(unicode)
此软件包内容的分类。此属性的返回值可能包括:“简历”,“信函”,“财务预测”,“提案”,“技术演示”等等。comments(unicode)
注意:在规范中名为“描述”。资源内容的说明。值可能包括摘要,目录,对内容图形表示的引用以及内容的自由文本帐户。content_status (unicode)
内容的状态。返回值可能包括“草稿”,“已审阅”和“最终”。created
(日期时间) 资源的创建日期。identifier(unicode)
在给定上下文中对资源的明确引用。keywords(unicode)
一组定界的关键字以支持搜索和索引。这通常是属性中其他地方不可用的术语列表。language (unicode)
资源知识内容的语言。last_modified_by (Unicode)
执行最后修改的用户。该标识是特定于环境的。示例包括姓名,电子邮件地址或员工ID。建议该值尽可能简洁。last_printed
(日期时间) 上次打印的日期和时间。modified
(日期时间) 文档更改的日期。revision(int)
修订号。该值可能指示保存或修订的数量,只要应用程序在每个修订后进行更新。subject (unicode)
文档内容的主题。title(unicode)
设置文档的名称。version(unicode)
版本指示符。该值由用户或应用程序设置。
DOCX 文档包含有文字、表格、图片等各种对象。 对于文字,是按 “节” 进行组织的。 在 DOCX 文档格式中,“节” 是页面格式的范围,对文档页面格式化的最小单位。 在“节”内,页面的宽度、空白间距、头尾内容都是按同样的方式定义的, 但并不表示是一样的,在 Word 中,对奇偶页进行了区分。
打开WORD, 不作任何设置的话,当在文档中插入分节符后,WORD其实默认将整个文档视为一“节”, 在页面设置窗口中预览效果中会看到“本节”分节符中存储了“节”的格式信息。
secs = dfile.sections
返回的 secs
是迭代对象,可以进行遍历:
for sec in secs:
print(sec.bottom_margin)
914400
如果在节中设置了页眉或页脚,可以使用下面的函数来获取 :
sec.header.paragraphs[0].text
type(dfile.paragraphs)
list
硬回车跟软回车:在文本编辑的时候,按Enter生成的叫硬回车, 表示一个段落到此结束;按住Shift+Enter是软回车,只作分行处理, 前后仍属于同一个段落。在Word中硬回车是一个折回来的箭头, 软回车是一个向下的箭头。在作段落设置时两者是有区别的。
获取文字内容可以通过迭代的方式。 可以看到下面索引为6的行,“段落”中间是有分行的。
for idx, para in enumerate(dfile.paragraphs):
print(idx, para.text)
0 从百草园到三味书屋 1 2 我家的后面有一个很大的园,相传叫作百草园。现在是早已并屋子一起卖给朱文公的子孙了,连那最末次的相见也已经隔了七八年,其中似乎确凿只有一些野草;但那时却是我的乐园。 3 4 这是鲁迅的母校:三味书屋 5 6 不必说碧绿的菜畦,光滑的石井栏,高大的皂荚树,紫红的桑椹;也不必说鸣蝉在树叶里长吟,肥胖的黄蜂伏在菜花上,轻捷的叫天子(云雀)忽然从草间直窜向云霄里去了。 单是周围的短短的泥墙根一带,就有无限趣味。 7 8
由于返回的类型是列表,段落也可以按索引获取 。
docx.paragraphs[i]
可以直接获得文章中的第 i
段,
可以按照输入的索引进行读取。
dfile.paragraphs[4].text
'这是鲁迅的母校:三味书屋\t'
file_tb=Document('/data/demo/tables.docx')
tb=file_tb.tables
type(tb)
list
返回的表格对象同样是列表,表示所有的表格。
通常,一次访问一行单元格比较容易,例如,从数据源填充可变长度的表时。
.rows
表的属性提供对各个行的访问,每个行都有一个 .cells
属性。
该 .cells
两个属性 Row
和 Column
支持索引访问,就像一个列表:
type(tb[0].rows)
docx.table._Rows
得到表格对象后,可以对表格的行、列进行遍历。表格对象的 rows
和 columns
集合是可迭代的,
因此可以在 for
循环中直接使用它们。
与 cells
行或列上的序列相同。
for r in tb[0].rows:
row_cnt = [cell.text for cell in r.cells]
print(row_cnt)
['date', 'type', '1001A'] ['20200420', 'AQI', '21'] ['20200420', 'PM2.5', '6'] ['20200420', 'PM2.5_24h', '35'] ['20200420', 'PM10', '11'] ['20200420', 'PM10_24h', '53'] ['20200420', 'SO2', '3']
下面是打印第2个表格中的内容:
for r in tb[1].rows:
row_cnt = [cell.text for cell in r.cells]
print(row_cnt)
['date', 'type', '1001A'] ['20200420', 'AQI', '21'] ['20200420', 'PM2.5', '6'] ['20200420', 'PM2.5_24h', '35'] ['20200420\n20200420\n20200420', 'PM10', '11'] ['20200420\n20200420\n20200420', 'PM10_24h', '53'] ['20200420\n20200420\n20200420', 'SO2', '3']
如果要对表中的行或列进行计数,可以使用 len()
方法:
len(tb[1].rows), len(tb[1].columns)
(7, 3)
使用 paragraphs
方法也同样查看表格内容。在单元格内,也是有段落的。
for r in tb[0].rows:
row_cnt = [cell.paragraphs[0].text for cell in r.cells]
print(row_cnt)
['date', 'type', '1001A'] ['20200420', 'AQI', '21'] ['20200420', 'PM2.5', '6'] ['20200420', 'PM2.5_24h', '35'] ['20200420', 'PM10', '11'] ['20200420', 'PM10_24h', '53'] ['20200420', 'SO2', '3']
可以看到处理表格的方式与 OpenpyXL 处理 XLSX 文档多有类似。
from docx.enum.style import WD_STYLE_TYPE
document=Document('/data/demo/demo1.docx')
styles = document.styles
下面对格式进行过滤,只列出类型为 PARAGRAPH
的格式:
paragraph_styles = [s for s in styles if s.type == WD_STYLE_TYPE.PARAGRAPH]
for style in paragraph_styles[:5]:
print(style.name , end = '; ' )
Normal; Heading 1; Heading 2; Heading 3; Heading 4;
除了段落,样式的类型还有字符 、表格、列表等。
在 DOCX 文档中,段落是一个很基本的单元,称为块对象;在一个段落中,里面可以有多种样式, 如加粗、斜体、下划线、字体不同颜色等,这些格式相同的内容, 在 docx 模块中是以行内对象进行组织。 换言之,一个行内对象是相同样式文本的延续,只要文本的格式没有改变, 那么就是一个行内对象,一旦改变了就是另外一个行内对象了。
行内对象是在段落对象中使用 runs
属性获得:
len(document.paragraphs[1].runs)
2
显示行内对象的文本内容:
document.paragraphs[1].runs[0].text
'在上个段落前在插入一个段落。'
document.paragraphs[1].runs[1].text
'这里格式进行了改变。'