>>> from env_helper import info; info()
页面更新时间: 2023-06-23 07:51:46
运行环境:
    Linux发行版本: Debian GNU/Linux 12 (bookworm)
    操作系统内核: Linux-6.1.0-9-amd64-x86_64-with-glibc2.36
    Python版本: 3.11.2

2.2. 使用python-docx 读取文档

使用 Python-docx 模块可以自动化的解决大部分操作。Python-docx 是一个很强大的包,可以用来读取和创建 DOCX 文档,包含段落、分页符、表格、图片、标题、样式等几乎所有的word文档中能常用的功能。

首先安装 python-docx 模块,通过 pip 命令:

pip install python-docx

安装完成后测试一下是否安装成功。

>>> import docx

DOCX 文档的内容有段落、表格等。

这一节先打开示例文件, 看一下能够解析出来哪些内容。

2.2.1. 打开一个文档

打开文档需要实例化 Document 对象,将文件路径作为参数:

>>> from docx import Document
>>> dfile = Document('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

2.2.2. 获取段落对象

DOCX 中的内容是按段落进行组织的。 虽然逻辑上段落是在“节”内,但实际上是独立的。 而且页眉、页脚的内容也是通过段落对象来获取。

paragraphs 可以获得全部的段落,类型为列表。相当于把文档内容放在了列表内。

>>> 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'

2.2.3. 读取表格对象

在示例文件中有表格。 表格对象通过 tables 属性获取,得到表格的列表。

_images/table.png

打开一个新的示例文件:

>>> file_tb=Document('tables.docx')
>>> tb=file_tb.tables
>>> type(tb)
list

返回的表格对象同样是列表,表示所有的表格。

通常,一次访问一行单元格比较容易,例如,从数据源填充可变长度的表时。.rows 表的属性提供对各个行的访问,每个行都有一个 .cells 属性。该 .cells 两个属性 RowColumn 支持索引访问,就像一个列表:

>>> type(tb[0].rows)
docx.table._Rows

得到表格对象后,可以对表格的行、列进行遍历。表格对象的 rowscolumns 集合是可迭代的, 因此可以在 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']
['20200420n20200420n20200420', 'PM10', '11']
['20200420n20200420n20200420', 'PM10_24h', '53']
['20200420n20200420n20200420', '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 文档多有类似。

2.2.4. 获取文档中的样式名称

DOCX 是富文件格式,除了内容,还有很多格式。 在这里要注意命名样式的概念。 命名样式,顾名思义,就是对样式或样式的组合进行了命名,以方便使用。 比如将“字号为小四、样式为粗体、右对齐”的段落样式命名为“命名样式”, 就可以在需要的地方将样式应用到段落上。

在 Word 软件中, 命名样式使用“样式管理器”进行管理。 在 Python 的 docx 模块中, 命名样式使用 styles 属性获取, 返回的类型为列表。

>>> from docx.enum.style import WD_STYLE_TYPE
>>> document=Document('./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;

除了段落,样式的类型还有字符 、表格、列表等。

2.2.5. 块对象与行内对象

在 DOCX 文档中,段落是一个很基本的单元,称为块对象;在一个段落中,里面可以有多种样式, 如加粗、斜体、下划线、字体不同颜色等,这些格式相同的内容, 在 docx 模块中是以行内对象进行组织。 换言之,一个行内对象是相同样式文本的延续,只要文本的格式没有改变, 那么就是一个行内对象,一旦改变了就是另外一个行内对象了。

行内对象是在段落对象中使用 runs 属性获得:

>>> len(document.paragraphs[1].runs)
2

显示行内对象的文本内容:

>>> document.paragraphs[1].runs[0].text
'在上个段落前在插入一个段落。'
>>> document.paragraphs[1].runs[1].text
'这里格式进行了改变。'