word的docx以xml格式实现Python自动化遇到图片无法正常显示以及word无法读取的内容报错的解决思路

环境

from xml.dom import minidom

目标

从一个word文档保留原格式复制到另一个word文档中,直接使用xml.dom去操作word文档,而不使用python-docx库。

Word格式

文件格式

word的docx本质是个压缩包,其中最主要的文档相关的内容使用xml格式存储的。当然绝大多数的文件都是以xml格式存在。

文件结构

├─1
│  │  [Content_Types].xml  包含了word要使用到的扩展
│  │
│  ├─docProps
│  │      app.xml
│  │      core.xml         包含文件作者
│  │
│  ├─word
│  │  │  document.xml      word文档中文字表格图片等详细内容,也是编辑word的主要文件
│  │  │  endnotes.xml      
│  │  │  fontTable.xml
│  │  │  footnotes.xml
│  │  │  settings.xml
│  │  │  styles.xml
│  │  │  webSettings.xml
│  │  │
│  │  ├─media              媒体文件夹中包含了word中需要用的的媒体文件
│  │  │      image1.gif
│  │  │
│  │  ├─theme              主题文件夹
│  │  │      theme1.xml
│  │  │
│  │  └─_rels              里面包含着document.xml引用的关系,将各个文件用rId联系
│  │          document.xml.rels  里面包含着图片的引用关系,如果你修改的图片不显示大概这里没有改
│  │
│  └─_rels
│          .rels
├─2
│  │  [Content_Types].xml
│  │
│  ├─docProps
│  │      app.xml
│  │      core.xml
│  │
│  ├─word
│  │  │  document.xml
│  │  │  endnotes.xml
│  │  │  fontTable.xml
│  │  │  footnotes.xml
│  │  │  settings.xml
│  │  │  styles.xml
│  │  │  webSettings.xml
│  │  │
│  │  ├─theme
│  │  │      theme1.xml
│  │  │
│  │  └─_rels
│  │          document.xml.rels
│  │
│  └─_rels
│          .rels
  • <w:p> 表示一个段落
  • <w:r> 表示一个样式串,指明它包括的文本的显示样式
  • <w:t> 表示真正的文本内容
  • <w:tbl> 表示一个表格
    • <w:tr> 表示表格一行
    • <w:tc> 表示一个cell,我立理解是单元格

其中文字被包含在<w:t>的节点下应该用firstchild来指向

问题复现

当我去从一个word文档的文字,图片以及公式保留格式复制到另一个word文档中,我首先是将源文档中document.xml相关节点复制到目标文档中。效果是一切ok的,除了照片无法显示,这时我就去查看源文件信息,发现还有media文件夹里的内容没有复制过去。于是复制图片到目标文档的对应目录中,结果还是无法显示,并且这时打开word文档会出现无法读取的内容。

于是两个问题需要解决

  1. 如何正确显示图片?
  2. 如何解决word报错?

正确显示图片

以下是doucument.xml里图片相关信息

<w:drawing>
    <wp:inline distT="0" distB="0" distL="0" distR="0"
        wp14:anchorId="77FAF658" wp14:editId="331AEBE1">
        <wp:extent cx="2842786" cy="2132374" />
        <wp:effectExtent l="0" t="0" r="0" b="1270" />
        <wp:docPr id="1" name="图片 1" />
        <wp:cNvGraphicFramePr>
            <a:graphicFrameLocks
                xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
                noChangeAspect="1" />
        </wp:cNvGraphicFramePr>
        <a:graphic
            xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
            <a:graphicData
                uri="http://schemas.openxmlformats.org/drawingml/2006/picture">
                <pic:pic
                    xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
                    <pic:nvPicPr>
                        <pic:cNvPr id="0" name="Picture 1" />
                        <pic:cNvPicPr>
                            <a:picLocks noChangeAspect="1"
                                noChangeArrowheads="1" />
                        </pic:cNvPicPr>
                    </pic:nvPicPr>
                    <pic:blipFill>
                        <a:blip r:embed="rId6">
                            <a:extLst>
                                <a:ext
                                    uri="{28A0092B-C50C-407E-A947-70E740481C1C}">
                                    <a14:useLocalDpi
                                        xmlns:a14="http://schemas.microsoft.com/office/drawing/2010/main"
                                        val="0" />
                                </a:ext>
                            </a:extLst>
                        </a:blip>
                        <a:srcRect />
                        <a:stretch>
                            <a:fillRect />
                        </a:stretch>
                    </pic:blipFill>
                    <pic:spPr bwMode="auto">
                        <a:xfrm>
                            <a:off x="0" y="0" />
                            <a:ext cx="2847489" cy="2135902" />
                        </a:xfrm>
                        <a:prstGeom prst="rect">
                            <a:avLst />
                        </a:prstGeom>
                        <a:noFill />
                        <a:ln>
                            <a:noFill />
                        </a:ln>
                    </pic:spPr>
                </pic:pic>
            </a:graphicData>
        </a:graphic>
    </wp:inline>
</w:drawing>

棘手的问题在于这个,图片的插入是通过这个id实现的

<a:blip r:embed="rId6">

<Relationship Id="rId6"
    Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
    Target="media/image1.gif" />

这个是document.xml.rels文件对应的

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
    <Relationship Id="rId8"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
        Target="theme/theme1.xml" />
    <Relationship Id="rId3"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings"
        Target="webSettings.xml" />
    <Relationship Id="rId7"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable"
        Target="fontTable.xml" />
    <Relationship Id="rId2"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings"
        Target="settings.xml" />
    <Relationship Id="rId1"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
        Target="styles.xml" />
    <Relationship Id="rId6"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"
        Target="media/image1.gif" />
    <Relationship Id="rId5"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes"
        Target="endnotes.xml" />
    <Relationship Id="rId4"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes"
        Target="footnotes.xml" />
</Relationships>

这个是文档2的

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
    <Relationship Id="rId3"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings"
        Target="webSettings.xml" />
    <Relationship Id="rId7"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"
        Target="theme/theme1.xml" />
    <Relationship Id="rId2"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings"
        Target="settings.xml" />
    <Relationship Id="rId1"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"
        Target="styles.xml" />
    <Relationship Id="rId6"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable"
        Target="fontTable.xml" />
    <Relationship Id="rId5"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes"
        Target="endnotes.xml" />
    <Relationship Id="rId4"
        Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes"
        Target="footnotes.xml" />
</Relationships>

这个rId并没有自己想的这么简单,主要是这个rId安排是按顺序的,整个页面的顺序。因此当从一个文件的图片复制到另一个文档中,需要考虑到rId冲突的问题。

解决思路

  1. 首先获取文档中的rid
  2. 再去document.xml.rels中找到源文件的信息比如Type,Target
  3. 然后我们要再去读取目标文件的document.xml.rels获取当前最高的rId数避免冲突
  4. 然后将文档中的rid相关信息加入到document.xml.rels中
  5. 然后修改文档中的rID添加到目标文档中

无法读取的报错

在这里插入图片描述

可疑点

[Content_Types].xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
    <Default Extension="gif" ContentType="image/gif" />
    <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />
    <Default Extension="xml" ContentType="application/xml" />
    <Override PartName="/word/document.xml"
        ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" />
    <Override PartName="/word/styles.xml"
        ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" />
    <Override PartName="/word/settings.xml"
        ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" />
    <Override PartName="/word/webSettings.xml"
        ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml" />
    <Override PartName="/word/footnotes.xml"
        ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" />
    <Override PartName="/word/endnotes.xml"
        ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml" />
    <Override PartName="/word/fontTable.xml"
        ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" />
    <Override PartName="/word/theme/theme1.xml"
        ContentType="application/vnd.openxmlformats-officedocument.theme+xml" />
    <Override PartName="/docProps/core.xml"
        ContentType="application/vnd.openxmlformats-package.core-properties+xml" />
    <Override PartName="/docProps/app.xml"
        ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" />
</Types>
    <Default Extension="gif" ContentType="image/gif" />

是不是要加入这个模块来实现gif的读取,要不然word读不了那张gif?

经过手动输入这行文档就不会报错了,推测是因为没有加入gif对应的插件,文件word读取不出gif所以报错。因此我只需要在[Content_Types].xml中引入需要的扩展信息才不会报错。

实现Python批量读取图片文字并保留格式,可以使用OCR技术对图片进行文字识别,然后将识别出的文本保存为相应格式的文件。 以下是一个示例代码,实现了批量读取指定文件夹下的所有图片并进行OCR文字识别,最后将识别结果保存为txt文件: ```python import pytesseract from PIL import Image import os # 设置tesseract的安装路径 pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe' # 指定待识别图片所在的文件夹路径 img_folder = r'C:\Users\username\Documents\images' # 定义一个函数,用于对单张图片进行OCR文字识别,并将识别结果保存到txt文件中 def recognize_text(image_path): # 打开图片 image = Image.open(image_path) # 进行OCR识别 text = pytesseract.image_to_string(image, lang='eng') # 保存识别结果到txt文件中 with open('result.txt', 'a') as f: f.write(text) f.write('\n\n') # 遍历指定文件夹下的所有图片,进行OCR文字识别 for root, dirs, files in os.walk(img_folder): for file in files: if file.endswith('.jpg') or file.endswith('.png'): image_path = os.path.join(root, file) recognize_text(image_path) ``` 如果要提取Word里的所有图片并批量转化格式,可以使用Pythondocx库来实现。以下是一个示例代码,实现了提取Word文档中的所有图片并将其转化为jpg格式图片: ```python from docx import Document # 打开Word文档 doc = Document('example.docx') # 定义一个函数,用于将Word文档中的图片保存为jpg格式图片 def save_image(image, filename): with open(filename, 'wb') as f: f.write(image) # 遍历文档中的所有图片,并将其转化为jpg格式图片 for i, image in enumerate(doc.inline_shapes): if 'image' in image._element.xml: # 获取图片数据 image_data = image._inline.graphic.graphicData.pic.blipFill.blip.getparent().getnext().getchildren()[0].getchildren()[0] # 将图片数据保存为jpg格式图片 save_image(image_data, f'image{i}.jpg') ``` 需要注意的是,由于Word文档中的图片可能采用了不同的格式,因此转化为jpg格式图片可能会失去一些细节。如果需要保留完整的图片格式,可以考虑将图片保存为原格式,或者使用第三方库进行格式转化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值