使用 python-docx 添加页码

Add page number using python-docx

我正在尝试使用 python-docx 在 word 文档的页脚中添加页码。到目前为止,我还没有找到如何做到这一点。 question address how to find a page number (or how you cannot). This 有人谈论创建模板并在其中添加页码。有没有办法在我使用 doc = Document() 创建的文档上添加页码?

我认为添加 PageNumber 是一项尚未实现的功能。

然而...

  1. 如果它是您想要添加页眉和页脚的现有文档 你可以打电话给VBA-macro。我最近发布了一种方法来做到这一点 ()
  2. 如果它是一个新文档那么你确实可以继续创建一个 首先模板文档,然后打开它并继续编辑为 由 scanny 描述。
  3. 这在其文档中引用了这个用例,但没有演示 如何 https://python-docx.readthedocs.io/en/latest/dev/analysis/features/header.html?highlight=page%20number
  4. 或者你可以试试这个 https://github.com/python-openxml/python-docx/issues/498

页脚中的自动 page-number 作为 字段 实现。字段在 python-docx 中还没有 API 支持,所以你不能用默认模板 (document = Document()) 创建的文档做你想做的事,至少不能通过制作 [=30] =] 呼叫.

两种可能的方法是创建一个在页脚中已有 page-number 的模板文档,然后从那里开始:

document = Document("my-template.docx")

或者创建一个解决方法函数,使用 low-level lxml 调用从 python-docx 对象获得的 XML 元素对象添加到 XML , 比如 paragraph._p.

Syafiqur__ 在他的回答中提供的链接可以帮助您使用后一种方法。

感谢 Syafiqur__ 和 scanny,我想出了一个添加页码的解决方案。

def create_element(name):
    return OxmlElement(name)

def create_attribute(element, name, value):
    element.set(ns.qn(name), value)


def add_page_number(run):
    fldChar1 = create_element('w:fldChar')
    create_attribute(fldChar1, 'w:fldCharType', 'begin')

    instrText = create_element('w:instrText')
    create_attribute(instrText, 'xml:space', 'preserve')
    instrText.text = "PAGE"

    fldChar2 = create_element('w:fldChar')
    create_attribute(fldChar2, 'w:fldCharType', 'end')

    run._r.append(fldChar1)
    run._r.append(instrText)
    run._r.append(fldChar2)

doc = Document()
add_page_number(doc.sections[0].footer.paragraphs[0].add_run())
doc.save("your_doc.docx")

我可以通过设置页脚段落的对齐方式使其显示在中心。所以我会把@max_max_mir的答案的最后几行修改为read

doc = Document()
add_page_number(doc.sections[0].footer.paragraphs[0].add_run())
doc.sections[0].footer.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
doc.save("your_doc.docx")

更一般地说,我可以通过修改上面的答案在页脚中显示 'Page x of y':

def create_element(name):
    return OxmlElement(name)


def create_attribute(element, name, value):
    element.set(nsqn(name), value)


def add_page_number(paragraph):
    paragraph.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER

    page_run = paragraph.add_run()
    t1 = create_element('w:t')
    create_attribute(t1, 'xml:space', 'preserve')
    t1.text = 'Page '
    page_run._r.append(t1)

    page_num_run = paragraph.add_run()

    fldChar1 = create_element('w:fldChar')
    create_attribute(fldChar1, 'w:fldCharType', 'begin')

    instrText = create_element('w:instrText')
    create_attribute(instrText, 'xml:space', 'preserve')
    instrText.text = "PAGE"

    fldChar2 = create_element('w:fldChar')
    create_attribute(fldChar2, 'w:fldCharType', 'end')

    page_num_run._r.append(fldChar1)
    page_num_run._r.append(instrText)
    page_num_run._r.append(fldChar2)

    of_run = paragraph.add_run()
    t2 = create_element('w:t')
    create_attribute(t2, 'xml:space', 'preserve')
    t2.text = ' of '
    of_run._r.append(t2)

    fldChar3 = create_element('w:fldChar')
    create_attribute(fldChar3, 'w:fldCharType', 'begin')

    instrText2 = create_element('w:instrText')
    create_attribute(instrText2, 'xml:space', 'preserve')
    instrText2.text = "NUMPAGES"

    fldChar4 = create_element('w:fldChar')
    create_attribute(fldChar4, 'w:fldCharType', 'end')

    num_pages_run = paragraph.add_run()
    num_pages_run._r.append(fldChar3)
    num_pages_run._r.append(instrText2)
    num_pages_run._r.append(fldChar4)

doc = Document()
add_page_number(doc.sections[0].footer.paragraphs[0])
doc.save("your_doc.docx")

我没有“声誉点数”来评论“Syafiqur__和scanny”max_max_mir的解决方案,所以我不得不写一个全新的评论。考虑到复杂的 xml 解决方案,我设计了一个技巧,将我选择的文本添加到页脚,然后按照我想要的方式在页脚一侧对齐页码。

因此,我使用 运行 创建页脚文本,并使用制表符相应地对齐它。然后我调用 max_max_mir 的函数:

my_footer_run = footer.paragraphs[0].add_run()
my_footer_run.text = "Copyright MyCompany  All Rights Reserved.\t\t"
add_page_number(my_footer_run)

...页码显示在相应的角落。在上面的示例中,页码显示在右侧,而原文显示在左侧。

非常感谢您的原始解决方案!

谢谢 max_max_mir 和 Utkarsh Dalal。这太棒了。我做了一些改动我在这里分享给需要它的人:

  1. 设置不同的首页(封面)
  2. 从0开始计算页数(封面不计算在内)
import docx
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.oxml import OxmlElement, ns

def create_element(name):
    return OxmlElement(name)
        
def create_attribute(element, name, value):
    element.set(ns.qn(name), value)
        
def add_page_number(run):
    fldStart = create_element('w:fldChar')
    create_attribute(fldStart, 'w:fldCharType', 'begin')

    instrText = create_element('w:instrText')
    create_attribute(instrText, 'xml:space', 'preserve')
    instrText.text = "PAGE"

    fldChar1 = create_element('w:fldChar')
    create_attribute(fldChar1, 'w:fldCharType', 'separate')

    fldChar2 = create_element('w:t')
    fldChar2.text = "2"

    fldEnd = create_element('w:fldChar')
    create_attribute(fldEnd, 'w:fldCharType', 'end')

    run._r.append(fldStart)

    run._r.append(instrText)
    run._r.append(fldChar1)
    run._r.append(fldChar2)

    run._r.append(fldEnd)


    add_page_number(doc.sections[0].footer.paragraphs[0].add_run())
    doc.sections[0].footer.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER

    doc.sections[0].different_first_page_header_footer = True
    sectPr = doc.sections[0]._sectPr
        
    pgNumType = OxmlElement('w:pgNumType')
    pgNumType.set(ns.qn('w:start'), "0")
    sectPr.append(pgNumType)