word文档.docx文件的python解析

一开始以为docx解析一切,后来发现远没有那么简单。

这里探讨的是docx文件,doc文件比较麻烦,最好在windows平台上处理成docx文件。两者的区别是doc格式比较早office 2003,存储的是二进制格式,docx存储的是xml文件等组成的压缩包,存储容量更小。

这篇文章没给代码,基于提示去问问大模型怎么写,根本记不住。

一、Document

from docx import Document

提取段落 .paragraps

提取表格 .tables

获取每个元素的类型 .element.body 其中.tag.endswith p为段落,tbl为表格,secPr为章节?,bookmarkStart、bookmarkEnd为书签

获取段落的分页信息 ._element.xml 包含lastRenderedPageBreak

获取样式 .style.name 可以获知其是一级标题?二级标题?

获取字号 从paragraps的runs中提取font.size

二、zipfile解压.docx文件

如果用终端vim xxx.docx,会看到一堆文件让选择,但是vim并不能真正显示出这些文件的内容。用zipfile可以将.docx的内容解压到一个文件夹

import zipfile
with zipfile.Zipfile(file_path,'r')as f:
    f.extractall(output_path)

文档中嵌套的文档可以在word/media或word/embeddings下找一找

主要文件在word/document.xml

页脚文件在word/footer*.xml

页眉文件在word/header*.xml

标号文件在word/numbering.xml

三、嵌套文件

有2种情况,后面链接到了本地一个文件,根据路径找到对应文件,或者文件作为附件真正被插入到文档中。

情况一:链接

用docx找一下oleObject

document = Document(f_path)
for rel in document.part.rels.values():
    if 'oleObject' in rel.reltype:
        print(rel.target_ref)

oleobject:代表工作表上的一个 ActiveX 控件或链接或嵌入的 OLE 对象

OLEObject 对象 (Excel) | Microsoft Learn

情况二:附件

用zipfile解压后找一下

四、基于langchain的RecursiveCharacterTextSplitter拆分文件

按照分隔符迭代拆分

139 深入解析 RecursiveCharacterTextSplitter 类 langchain_text_splitters.charater.py-CSDN博客

五、基于langchain的 Docx2textLoader

本质是用docx2txt(一个可以用pip安装的库)提取page_content信息,再用自定义的Document进行管理。docx2txt的功能具体看:

缺点:

1、没有分离页眉页脚

2、不能保留表格,每个单元格都变成了一行

3、附件没有

六、基于ragflow的RAGFlowDocxParser

本质还是用docx实现的,考虑了段落的分页情况,可以提取起止页间的段落

七、docx2txt

lainchain的底层,可以对word文件解压后提取页眉、主文本、页脚、图片

八、复杂合并单元格的表格

        从docx的xml源文件解析复杂表格,试过多种开源的docx解析方案,对复杂表格的解析都不好,会丢失格式信息。尝试自己来解析,获得准确的列信息,解析word/document.xml文件,获得一个大xml,可以发现,段落和表格的信息都在其中,奇怪的是,这个xml会进行奇奇怪怪的断句。将表格前后的xml内容复制,在xml在线解析网页中格式化,可以看到清晰的表格格式。表示表格,是行信息,是单元格信息(cells),是文本信息。

1、合并行列的单元格

用xml.etree.ElementTree解析后所有数据是一个tree的形式,而不是list的形式,用findall、find、get来获得下一级的信息。列合并看gridSpan,可以直接看到列合并数量,如指2个单元格合并为1个。行合并看VMerge,指行合并的首行,指行合并的非首行。

2、单元格内的段落

    上文说到xml会进行奇奇怪怪的断句,所以一般会用‘’.join进行拼接,但是暴力拼接会丢失换行的段落信息,解决办法是在单元格内找段落,段落内进行拼接。

# 表
for table in tables:
    # 行
    rows = table.findall('.//w:tr',ns)
    for row in rows:
        #单元格
        cells = row.findall('.//w:tc',ns)
        for cell in cells:
            # 段落
            ps = cell.findall('.//w:p',ns)
            for p in ps:
                # 文本
                t = ''.join([text.text for text in p.findall('.//w:t',ns)])
    
    

九、文本框

参考Python批量提取docx格式Word文档中所有文本框内的文本_python怎么复制word文档中的文本框和内容-CSDN博客缺陷是不知道文本框的位置,有的文档是左右2个文本框人为做了分栏,但是脚本提取时,可能先提取到右边的再提取到左边的。

word文档.docx文件的python解析_第1张图片

十、自动编号

        自动编号时,有多种样式,在document.xml中没有直接记录其样式及内容,需要另外解析word/numbering.xml文件。

Python实现自动编号解析Word文档-物联沃-IOTWORD物联网

参考这篇文章,核心思想是提取document.xml中的ilvl和numId,然后去numbering.xml找对应的lvlText,接着统计出现次数进行渲染

document.xml中的ilvl和numId:

 
      
      
    

style示例:

{'start': '1', 'numFmt': 'decimal', 'lvlText': '%1.', 'lvlJc': 'left'}

渲染示例:

lvlText = lvlText.replace(f'%{i + 1}', str(cache[(abstractId, i)]))

渲染时会遇到一点奇怪的问题numbering.xml中记录的lvlText和word中不一样。

你可能感兴趣的:(word)