123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- from docx import Document
- from docx.shared import Pt
- from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK
- from docx.shared import RGBColor
- from docx.oxml.ns import qn
- from docx.oxml import OxmlElement
- doc = Document()
- # 添加标题和书签
- def add_title_with_bookmark(doc, text, style, bookmark_id):
- paragraph = doc.add_paragraph(text, style=style)
- run = paragraph.add_run()
- tag = run._r
- start = OxmlElement('w:bookmarkStart')
- start.set(qn('w:id'), str(bookmark_id))
- start.set(qn('w:name'), text)
- tag.append(start)
- tr = OxmlElement('w:r')
- tr.text = ''
- tag.append(tr)
- end = OxmlElement('w:bookmarkEnd')
- end.set(qn('w:id'), str(bookmark_id))
- end.set(qn('w:name'), text)
- tag.append(end)
- # 开始写入文档
- doc.add_paragraph('文档标题')
- doc.add_paragraph('目录')
- # 标记目录的位置
- catalog_p = doc.add_paragraph('')
- # 写入标题和段落
- add_title_with_bookmark(doc, '第一部分', style='Heading 1', bookmark_id='1')
- add_title_with_bookmark(doc, '1.二级标题', style='Heading 2', bookmark_id='2')
- for i in range(15):
- doc.add_paragraph('<<p{}>>'.format(str(i)))
- add_title_with_bookmark(doc, '第二部分', style='Heading 1', bookmark_id='3')
- add_title_with_bookmark(doc, '1.二级标题', style='Heading 2', bookmark_id='4')
- for i in range(15):
- doc.add_paragraph('<<p{}>>'.format(str(i)))
- add_title_with_bookmark(doc, '2.二级标题', style='Heading 2', bookmark_id='5')
- for i in range(15):
- doc.add_paragraph('<<p{}>>'.format(str(i)))
- add_title_with_bookmark(doc, '3.二级标题', style='Heading 2', bookmark_id='6')
- # 开始写入目录
- # 目录开头增加值域,方便手动更新整个目录。自动生成的目录标题包含在值域中。
- toc_paragraph = catalog_p.insert_paragraph_before() # 在标记的目录位置前添加段落
- r1 = toc_paragraph.add_run()
- toc_field = OxmlElement('w:fldChar')
- toc_field.set(qn('w:fldCharType'), 'begin')
- r1._r.append(toc_field)
- r2 = toc_paragraph.add_run()
- toc_field = OxmlElement('w:instrText')
- toc_field.set(qn('xml:space'), 'preserve')
- toc_field.text = 'TOC \\o "1-3" \\h \\z '
- r2._r.append(toc_field)
- r3 = toc_paragraph.add_run()
- toc_field = OxmlElement('w:fldChar')
- toc_field.set(qn('w:fldCharType'), 'separate')
- r3._r.append(toc_field)
- # 自动生成目录内容,不包含页码
- for paragraph in doc.paragraphs:
- if 'Heading' in paragraph.style.name:
- b = paragraph._element.findall('.//' + qn('w:bookmarkStart'))
- bookmark_name = b[0].get(qn('w:name'))
- text = paragraph.text
- level = int(paragraph.style.name[-1])
- # print(text, bookmark_name)
- toc_paragraph = catalog_p.insert_paragraph_before(style='Normal')
- # 二级标题设置缩进
- if level == 2:
- toc_paragraph.paragraph_format.first_line_indent = Pt(24)
- # 设置制表符,可显示页码前的"…………"
- tabs = OxmlElement('w:tabs')
- tab1 = OxmlElement('w:tab')
- tab1.set(qn('w:val'), "left")
- tab1.set(qn('w:leader'), "dot")
- tab1.set(qn('w:pos'), "8400")
- tabs.append(tab1)
- toc_paragraph._p.pPr.append(tabs)
- # toc_paragraph若未设定style,toc_paragraph._p没有pPr属性,需注释前一句代码,使用以下语句
- # pPr = OxmlElement('w:pPr')
- # pPr.append(tabs)
- # toc_paragraph._p.append(pPr)
- hyperlink = OxmlElement('w:hyperlink')
- hyperlink.set(qn('w:anchor'), bookmark_name)
- hyperlink.set(qn('w:history'), '1')
- hr1 = OxmlElement('w:r')
- rPr = OxmlElement('w:rPr')
- rStyle = OxmlElement('w:rStyle')
- rStyle.set(qn('w:val'), "a4")
- rPr.append(rStyle)
- hr1.text = text
- hr1.append(rPr)
- hyperlink.append(hr1)
- hr2 = OxmlElement('w:r')
- rPr = OxmlElement('w:rPr')
- fldChar = OxmlElement('w:fldChar')
- fldChar.set(qn('w:fldCharType'), 'begin')
- hr2.append(rPr)
- hr2.append(fldChar)
- hyperlink.append(hr2)
- hr3 = OxmlElement('w:r')
- rPr = OxmlElement('w:rPr')
- instrText = OxmlElement('w:instrText')
- instrText.set(qn('xml:space'), 'preserve')
- instrText.text = ' PAGEREF {} \h '.format(bookmark_name)
- hr3.append(rPr)
- hr3.append(instrText)
- hyperlink.append(hr3)
- hr4 = OxmlElement('w:r')
- rPr = OxmlElement('w:rPr')
- fldChar = OxmlElement('w:fldChar')
- fldChar.set(qn('w:fldCharType'), 'separate')
- hr4.append(rPr)
- hr4.append(fldChar)
- hyperlink.append(hr4)
- hrt = OxmlElement('w:r')
- tab = OxmlElement('w:tab')
- hrt.append(tab)
- hyperlink.append(hrt)
- hr5 = OxmlElement('w:r')
- rPr = OxmlElement('w:rPr')
- hr5.text = ''
- hr5.append(rPr)
- hyperlink.append(hr5)
- hr6 = OxmlElement('w:r')
- rPr = OxmlElement('w:rPr')
- fldChar = OxmlElement('w:fldChar')
- fldChar.set(qn('w:fldCharType'), 'end')
- hr6.append(rPr)
- hr6.append(fldChar)
- hyperlink.append(hr6)
- toc_paragraph._p.append(hyperlink)
- # 目录结尾的值域
- toc_paragraph = catalog_p.insert_paragraph_before()
- r4 = toc_paragraph.add_run()
- toc_field = OxmlElement('w:fldChar')
- toc_field.set(qn('w:fldCharType'), 'end')
- r4._r.append(toc_field)
- # 分页
- break_page_p = catalog_p.insert_paragraph_before()
- break_page_p.add_run().add_break(WD_BREAK.PAGE)
- doc.save(r'result.docx')
|