我想用Python-docx在word文档的页脚添加一个页码。到目前为止,我还没能找到如何做到这一点。 This 问题涉及如何找到页码(或如何找不到)。 This 有一篇文章谈到了创建一个模板并在那里添加页码。有没有办法在我用doc = Document()创建的文档上添加页码?
感谢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")
Crypto营长
:
你知道如何让它出现在中间吗?我想从第3页开始计数,怎么做?
Garrett
:
这对我来说是有效的,必须添加导入
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
发布于
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添加为文本,而不必建立整个结构?
scanny
:
你说的 "整个结构 "是什么意思?页脚已经在那里了,你只需要把它的一个段落中的页面字段放在正确的位置上。Syafiqur__提供的最后一个链接演示了如何做到这一点。
github.com/python-openxml/python-docx/issues/498
谢谢!我说的整个结构,是指一次性添加整个XML字符串,而不是一块一块地建立它(先添加一个标签,然后是它的属性,等等)。我将尝试Syafiqur__提供的最后一个链接中的方法,但从我看到的footer2.xlm这个词来看,创建页面的内容还有很多#。
scanny
:
啊,我明白了,好吧,两种方法都可以,但我一般更喜欢在不止一个元素或属性的时候一次性添加。你可以把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
发布于
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__
发布于
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
发布于
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
发布于
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
发布于
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')