添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
性感的小蝌蚪  ·  EasyCV ...·  2 年前    · 
坚韧的稀饭  ·  java - ...·  2 年前    · 

使用python-docx添加页码

10 人关注

我想用Python-docx在word文档的页脚添加一个页码。到目前为止,我还没能找到如何做到这一点。 This 问题涉及如何找到页码(或如何找不到)。 This 有一篇文章谈到了创建一个模板并在那里添加页码。有没有办法在我用doc = Document()创建的文档上添加页码?

python
ms-word
python-docx
max_max_mir
max_max_mir
发布于 2019-06-19
7 个回答
max_max_mir
max_max_mir
发布于 2022-10-01
已采纳
0 人赞同

感谢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")
    
你知道如何让它出现在中间吗?我想从第3页开始计数,怎么做?
这对我来说是有效的,必须添加导入 from docx.oxml import OxmlElement, ns
同时,您可以添加总页数,将 "PAGE" 替换为 "NUMPAGES"
要把页码放在中间,你需要设置段落对齐。替换代码0】,然后再添加一个单元。要在第一页以外的其他页开始编号,你需要添加一个新的部分,例如: doc.add_section(WD_SECTION.NEW_PAGE) ,并且用 doc.sections[1].footer.is_linked_to_previous = False 把它的页脚与前一个部分的链接取消。
scanny
scanny
发布于 2022-10-01
0 人赞同

页脚中的自动页码是作为一个 field .字段在 python-docx 中还没有API支持,所以你不能对从默认模板( document = Document() )创建的文档做你想做的事,至少不能通过API调用。

两种可能的方法是创建一个在页脚已经有页码的模板文件,然后从那里开始。

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

或者创建一个变通函数,使用低级别的lxml调用从python-docx对象获得的XML元素对象来添加到XML中,比如paragraph._p

Syafiqur__在其答案中提供的链接可以帮助你采用后一种方法。

谢谢你的快速回复。我手动添加了一个页码,看看它在.xml文件中被储存在哪里。我注意到我的docx有3个页脚xml - footer1.xml,footer2.xml和footer3.xml。在页脚2中,我看到一堆似乎与页脚有关的xml。有没有一种方法可以简单地使用低级别的lxml调用将xml添加为文本,而不必建立整个结构?
你说的 "整个结构 "是什么意思?页脚已经在那里了,你只需要把它的一个段落中的页面字段放在正确的位置上。Syafiqur__提供的最后一个链接演示了如何做到这一点。 github.com/python-openxml/python-docx/issues/498
谢谢!我说的整个结构,是指一次性添加整个XML字符串,而不是一块一块地建立它(先添加一个标签,然后是它的属性,等等)。我将尝试Syafiqur__提供的最后一个链接中的方法,但从我看到的footer2.xlm这个词来看,创建页面的内容还有很多#。
啊,我明白了,好吧,两种方法都可以,但我一般更喜欢在不止一个元素或属性的时候一次性添加。你可以把XML形成一个字符串,然后用 parse_xml() 函数把它变成一个准备插入的元素。这将是一个在 python-docx 本身中完成的例子。 github.com/python-openxml/python-docx/blob/master/docx/oxml/... . 如果你遇到麻烦,这将是一个很好的附加问题;如何使这种方法发挥作用,是一个相当多的问题。
再次感谢您的帮助!我会试试的。Btw,我正在试图弄清楚github.com/python-openxml/python-docx/issues/498中的qn(例如qn('w:fldCharType'))是干什么的,或者它是否是python-docx包的一部分。顺便说一下,如果我成功地创建了页码,我会尝试把这些函数粘贴在这里,这样它就可以回到包里了。
Utkarsh Dalal
Utkarsh Dalal
发布于 2022-10-01
0 人赞同

我能够通过设置页脚段落的对齐方式使其出现在中心位置。因此,我将@max_max_mir的答案的最后几行修改为

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")

更普遍的是,我通过修改上面的答案,能够在页脚显示 "第x页,第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__
Syafiqur__
发布于 2022-10-01
0 人赞同

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

However...

  • If it is an existing document you want to add headers and footers to you can call a VBA-macro. I recently posted a way to do that ( https://stackoverflow.com/a/44767400/7386332 )
  • If it is a new document then you can indeed go on and create a template document first and then open it up and continue editing as described by scanny.
  • This refers to this use case in its docs but doesn't demonstrate https://python-docx.readthedocs.io/en/latest/dev/analysis/features/header.html?highlight=page%20number
  • Or you can try this https://github.com/python-openxml/python-docx/issues/498
  • mhagr
    mhagr
    发布于 2022-10-01
    0 人赞同

    谢谢max_max_mir和Utkarsh Dalal。这真是太好了。我做了一些修改,在此分享给需要的人。

  • set different first page (cover page)
  • start counting pages from 0 (cover page is not counted)
  • 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)
        
    Sp_V
    Sp_V
    发布于 2022-10-01
    0 人赞同

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

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

    my_footer_run = footer.paragraphs[0].add_run()
    add_page_number(my_footer_run)
    

    ...而页码则显示在适当的角落。在上面的例子中,页码显示在右边,而原文则显示在左边。

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

    看起来你可能在寻找的是 分页符 .标签止点是标尺上的一个定义位置,当你添加一个标签时,my_footer_run.add_tab(),那么打字区就会跳到定义的位置。你也可以为标签止点设置文字的对齐方式。
    amargulis
    amargulis
    发布于 2022-10-01
    0 人赞同

    我发现最简单的做法是在Word中按照我的要求准备模板,包括页码、颜色等;然后阅读;再修改并保存。

    from docx import Document
    folder_data = 'C:\\Users\\...\\Data\\'
    folder_output = 'C:\\Users\\...\\Output\\'
    client_ = 'Client 1'; price_ = 99.99
    document_ = Document(f'{folder_data}invoiceTemplate.docx')
    document_.paragraphs[3].add_run(f'{price_} EUR')