Текст-заменить в docx и сохранить измененный файл с помощью python-docx

Я пытаюсь использовать модуль python-docx чтобы заменить слово в файле и сохранить новый файл с оговоркой, что новый файл должен иметь точно такое же форматирование, как и старый файл, но с замененным словом. Как мне это сделать?

модуль docx имеет savedocx, который принимает 7 входов:

  • документ
  • coreprops
  • appprops
  • contenttypes
  • websettings
  • wordrelationships
  • выход

Как сохранить все в исходном файле, за исключением замененного слова?

6 ответов


как кажется, Docx для Python не предназначен для хранения полного Docx с изображениями, заголовками, ... , но содержит только внутреннее содержание документа. Поэтому нет простого способа сделать это.

правда, вот как вы могли бы сделать это:

во-первых, посмотрите на тег docx wiki:

это объясняет, как файл docx может быть распакован: вот как выглядит типичный файл:

+--docProps
|  +  app.xml
|  \  core.xml
+  res.log
+--word //this folder contains most of the files that control the content of the document
|  +  document.xml //Is the actual content of the document
|  +  endnotes.xml
|  +  fontTable.xml
|  +  footer1.xml //Containst the elements in the footer of the document
|  +  footnotes.xml
|  +--media //This folder contains all images embedded in the word
|  |  \  image1.jpeg
|  +  settings.xml
|  +  styles.xml
|  +  stylesWithEffects.xml
|  +--theme
|  |  \  theme1.xml
|  +  webSettings.xml
|  \--_rels
|     \  document.xml.rels //this document tells word where the images are situated
+  [Content_Types].xml
\--_rels
   \  .rels

Docx получает только одну часть документа, в метод opendocx

def opendocx(file):
    '''Open a docx file, return a document XML tree'''
    mydoc = zipfile.ZipFile(file)
    xmlcontent = mydoc.read('word/document.xml')
    document = etree.fromstring(xmlcontent)
    return document

он получает только документ.XML-файл.

что я рекомендую вам сделать следующее:

  1. получить содержимое документа с помощью * * opendocx*
  2. заменить документ.XML-файле с помощью тега advReplace метод
  3. откройте docx как zip и замените документ.содержимое xml по новому содержимому xml.
  4. закройте и выведите сжатый файл (переименовав его в выход.файлы DOCX)

Если у вас есть узел.JS установлен, сообщаю, что я работал над DocxGenJS который является шаблоном для docx документов, библиотека находится в активной разработке и будет выпущена в ближайшее время как модуль узла.


это сработало для меня:

def docx_replace(old_file,new_file,rep):
    zin = zipfile.ZipFile (old_file, 'r')
    zout = zipfile.ZipFile (new_file, 'w')
    for item in zin.infolist():
        buffer = zin.read(item.filename)
        if (item.filename == 'word/document.xml'):
            res = buffer.decode("utf-8")
            for r in rep:
                res = res.replace(r,rep[r])
            buffer = res.encode("utf-8")
        zout.writestr(item, buffer)
    zout.close()
    zin.close()

вы используете модуль docx от здесь?

Если да, то модуль docx уже предоставляет такие методы, как replace, advReplace и т. д., которые могут помочь вам достичь вашей задачи. Обратитесь к исходный код для получения более подробной информации о воздействии методов.


Я разветвил РЕПО python-docx здесь, который сохраняет все существующие данные в файле docx, включая форматирование. Надеюсь, это то, что вы ищете.


в дополнение к @ramil вам нужно избежать некоторых символов, прежде чем размещать их в качестве строковых значений в XML, поэтому это сработало для меня:

def escape(escapee):
  escapee = escapee.replace("&", "&")
  escapee = escapee.replace("<", "&lt;")
  escapee = escapee.replace(">", "&gt;")
  escapee = escapee.replace("\"", "&quot;")
  escapee = escapee.replace("'", "&apos;")
return escapee

from docx import Document
file_path = 'C:/tmp.docx'
document = Document(file_path)

def docx_replace(doc_obj, data: dict):
    """example: data=dict(order_id=123), result: {order_id} -> 123"""
    for paragraph in doc_obj.paragraphs:
        for key, val in data.items():
            key_name = '{{{}}}'.format(key)
            if key_name in paragraph.text:
                paragraph.text = paragraph.text.replace(key_name, str(val))
    for table in doc_obj.tables:
        for row in table.rows:
            for cell in row.cells:
                docx_replace(cell, data)

docx_replace(document, dict(order_id=123, year=2018, payer_fio='payer_fio', payer_fio1='payer_fio1'))
document.save(file_path)