前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[PYTHON] 自动化办公03 python内置xml包处理docx和xlsx文档

[PYTHON] 自动化办公03 python内置xml包处理docx和xlsx文档

原创
作者头像
大大刺猬
发布2024-03-28 19:53:04
2610
发布2024-03-28 19:53:04
举报
文章被收录于专栏:大大刺猬大大刺猬

背景

天天写方案,天天写方案, 写到怀疑人生.....

所以我们可以使用python来帮我们实现那些重复度很高的方案.

由于 环境不支持连接外网, 无第三方包. 那些好用的word处理包都无法使用, 难度一下子就上来了..... 好歹有python3 (py2的话,难度更上一层楼.)

注: 由于代码都是在内网写的, 无法提供完整的例子了. 本文主要偏向于一些xml处理word/xlsx的坑.

分析

docx 是doc的扩展, xlsx是xls的扩展, 都是为了和其它厂商竞争为了兼容性才出现的标准格式. 本质是一个zip文件.

我们一个个来看

DOCX

先来看word, 也就是docx格式的文件, 格式参考如下

结构查看

我们使用zip解压docx文件, 就能看到如下信息.

docProps/app.xml 是一些应用信息, 比如厂商

docProps/core.xml 是一些文件基础信息, 比如是谁修改的, 什么时候修改的. 所以传word文件的时候要注意隐私安全

docProps/custom.xml 是一些自定义信息, 比如KEY

word/media 是一些媒体资源, 比如图片

word/theme 是一些主题

word/document.xml 是我们的文档 . 这个就是本文的重点.

代码语言:md
复制
├── [Content_Types].xml
├── docProps
│   ├── app.xml
│   ├── core.xml
│   └── custom.xml
├── _rels
└── word
    ├── document.xml
    ├── fontTable.xml
    ├── media
    │   ├── image1.png
    │   ├── image2.png
    │   ├── image3.png
    │   ├── image4.png
    │   ├── image5.png
    │   ├── image6.png
    │   ├── image7.png
    │   └── image8.png
    ├── _rels
    │   └── document.xml.rels
    ├── settings.xml
    ├── styles.xml
    └── theme
        └── theme1.xml

document.xml文件解析 读数据

我们使用浏览器 打开xml文件(直接把xml文件拖到浏览器就行) 会看到一个类似如下的格式

这是一个xml文件, 我们可以使用 python 的xml.dom.minidom 来解析这个文件

由于是zip文件的, 所以得先用zipfile解压文件, 在读里面的document.xml文件

代码语言:python
代码运行次数:0
复制
import zipfile
import os,sys
from xml.dom import minidom
filename = "aaaa.docx" #我们的word文件

#命名空间
namespace = {"w":"http://schemas.openxmlformats.org/wordprocessingml/2006/main"}
with zipfile.ZipFile(filename,'r') as docx:
    with docx.open('word/document.xml', 'r') as docx_xml:
        xml_content = docx_xml.read()
        root = minidom.parseString(xml_content).documentElement
        body = root.childNodes[0]

w:body 就是 我们的文档主要部分

w:p 就是段落

w:tbl 就是 表格

w:t 就是记录文字的

其它的标签基本上就是样式之类的了.

比如我们要读取所有的数据的话. 直接使用 getElementsByTagName('w:t')就可以

代码语言:python
代码运行次数:0
复制
for x in body.getElementsByTagName('w:t'): #之前w和t之间忘记加: 排查了半小时....
    print(x.firstChild.nodeValue) #w:t不是具体的数据, 里面实际上还有个 node 叫 #text

document.xml文件解析 写数据

读数据很简单, 直接遍历 w:t就行 但是写数据就麻烦了. 尤其是新增数据, 看着那一对对复杂的格式, 简直头痛.

1. 好在我们可以使用 cloneNode 来克隆node. (elementree就没得, 巨坑, 啊, 不剧透了.)

所以我们可以遍历 w:t 匹配值, 如果匹配上了, 就返回 w:t 的最近的w:p (段落) 只有w:t不方便, 通常建议直接复制一个段落. 不然格式太复杂了. 如果是表格的话, 只要行就行.

2. 然后使用 insertBefore 在指定的地方插入即可.

3. 不要的数据可以使用removeChild来删除.

4. 修改完数据后, 就是写回word文件了. 我们重新打开word, 如果是document.xml文件就使用我们修改后的, 否则直接写回即可.

思路就是这么个思路, 我们还是来看下例子吧.

代码语言:python
代码运行次数:0
复制

#先找到一个node. 我这里就随便找了
ref_node = body.getElementsByTagName('w:t')[12].parentNode.parentNode

# 克隆一个node 并修改数据
new_node = ref_node.cloneNode(1)
new_node.firstChild.firstChild.firstChild.nodeValue = "使用minidom修改的数据"

# 插入到指定位置
ref_node.parentNode.insertBefore(new_node, ref_node)

#删除(我这里就不演示了)
#ref_node.parentNode.removeChild(ref_node)

接下来就是保存了.

代码语言:python
代码运行次数:0
复制
with zipfile.ZipFile(filename,'r') as zin:
	with zipfile.ZipFile('newfile20240328.docx','w') as zout:
		for item in zin.infolist():
			if item.filename == "word/document.xml": #如果是document 就使用我们修改过的那个
				zout.writestr(item,root.toxml().encode())
			else:
				zout.writestr(item, zin.read(item.filename))

document.xml文件解析 验证

自己验证即可.

XLSX

xlsx内容要简单些(没得那么多样式了). 但坑也最多.

所以我们解析xlsx相关的xml文件就使用 xml.etree.ElementTree 来做(坑的开始.)

我们还是使用zip解压查看

代码语言:md
复制
├── [Content_Types].xml
├── docProps
│   ├── app.xml
│   ├── core.xml
│   └── custom.xml
├── _rels
└── xl
    ├── _rels
    │   └── workbook.xml.rels
    ├── sharedStrings.xml
    ├── styles.xml
    ├── theme
    │   └── theme1.xml
    ├── workbook.xml
    └── worksheets
        ├── sheet1.xml
        ├── sheet2.xml
        └── sheet3.xml

docProps 和 word那个差不多.

我们主要看 xl目录.

xl/sharedStrings.xml 是共享字符, 我们的实际数据就是放这里的

xl/worksheets/sheet1.xml 就是我们的sheet

xl/workbook.xml 记录sheet之类的信息的

sharedStrings.xml

这个xml文件很简单. 就是字符串列表.

这个文件主要是记录那些共享值, 所以这里的值尽量唯一. index就是sheet里面记录的值, 所以这个位置也很重要.

基本上就是遍历一下, 再shardStrings里面就返回index , 否则就插入, 并返回len()-1

就不写例子了.

xl/worksheets/sheet1.xml

其实这个文件格式也比较简单. 数据就放在 sheetData 里面的.

sheetData 类似table

row 就是行

c 就是col 列. v 就是value (是字符串, 即使看到的是数字, 也是字符串(小坑))

row里面的spans 就是记录这一行数据的列数. r 是行号(从1开始)

c里面的 r 是记录列号, 就是excel里面的那个A1 A2 t记录数据类型, 比如 t='s' 就标识数据是shareding的, 就得去sharedStrings.xml里面找

xl/worksheets/sheet1.xml 读写

读: 比较简单, 直接遍历即可. 也可以世界使用index来访问.

比如 xml.etree.elementtree()[5][ROWNO][COLNO].text就是 ROWNO行COLNO列的值.

修改的话, 得先 deepcopy 出来, 然后修改, 全部修改完后, 再复制回去. 不然数据就是乱的. 这是巨坑

写回xlsx文件和word一样的. 只是多个文件(sharedStrings.xml)而已. 所以这里就不演示了.

总结

1. 虽然python自带的xml能操作docx和xlsx文档, 但不建议这么做, 太痛苦了.

2. 实际编写代码的时候, 要根据自己的情况抽象出多个方法, 这样写起来就方便些. 比如( 复制某一行,然后修改指定列的数据, 最后在行尾插入 这一系列操作抽象为一个方法. 相同的操作就很简单了. 就是各种循环...)

3. 注意环境, docx可能存在namespace的问题.

4. xlsx 数据部分不显示的话, 大概率就是row的行号或者c的列号有问题. 再不济就是没有deepcopy, 而是直接遍历修改原来的值.

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 分析
    • DOCX
      • 结构查看
      • document.xml文件解析 读数据
      • document.xml文件解析 写数据
      • document.xml文件解析 验证
    • XLSX
      • sharedStrings.xml
      • xl/worksheets/sheet1.xml
      • xl/worksheets/sheet1.xml 读写
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档