demo.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. from docx import Document
  2. from docx.shared import Pt
  3. from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK
  4. from docx.shared import RGBColor
  5. from docx.oxml.ns import qn
  6. from docx.oxml import OxmlElement
  7. doc = Document()
  8. # 添加标题和书签
  9. def add_title_with_bookmark(doc, text, style, bookmark_id):
  10. paragraph = doc.add_paragraph(text, style=style)
  11. run = paragraph.add_run()
  12. tag = run._r
  13. start = OxmlElement('w:bookmarkStart')
  14. start.set(qn('w:id'), str(bookmark_id))
  15. start.set(qn('w:name'), text)
  16. tag.append(start)
  17. tr = OxmlElement('w:r')
  18. tr.text = ''
  19. tag.append(tr)
  20. end = OxmlElement('w:bookmarkEnd')
  21. end.set(qn('w:id'), str(bookmark_id))
  22. end.set(qn('w:name'), text)
  23. tag.append(end)
  24. # 开始写入文档
  25. doc.add_paragraph('文档标题')
  26. doc.add_paragraph('目录')
  27. # 标记目录的位置
  28. catalog_p = doc.add_paragraph('')
  29. # 写入标题和段落
  30. add_title_with_bookmark(doc, '第一部分', style='Heading 1', bookmark_id='1')
  31. add_title_with_bookmark(doc, '1.二级标题', style='Heading 2', bookmark_id='2')
  32. for i in range(15):
  33. doc.add_paragraph('<<p{}>>'.format(str(i)))
  34. add_title_with_bookmark(doc, '第二部分', style='Heading 1', bookmark_id='3')
  35. add_title_with_bookmark(doc, '1.二级标题', style='Heading 2', bookmark_id='4')
  36. for i in range(15):
  37. doc.add_paragraph('<<p{}>>'.format(str(i)))
  38. add_title_with_bookmark(doc, '2.二级标题', style='Heading 2', bookmark_id='5')
  39. for i in range(15):
  40. doc.add_paragraph('<<p{}>>'.format(str(i)))
  41. add_title_with_bookmark(doc, '3.二级标题', style='Heading 2', bookmark_id='6')
  42. # 开始写入目录
  43. # 目录开头增加值域,方便手动更新整个目录。自动生成的目录标题包含在值域中。
  44. toc_paragraph = catalog_p.insert_paragraph_before() # 在标记的目录位置前添加段落
  45. r1 = toc_paragraph.add_run()
  46. toc_field = OxmlElement('w:fldChar')
  47. toc_field.set(qn('w:fldCharType'), 'begin')
  48. r1._r.append(toc_field)
  49. r2 = toc_paragraph.add_run()
  50. toc_field = OxmlElement('w:instrText')
  51. toc_field.set(qn('xml:space'), 'preserve')
  52. toc_field.text = 'TOC \\o "1-3" \\h \\z '
  53. r2._r.append(toc_field)
  54. r3 = toc_paragraph.add_run()
  55. toc_field = OxmlElement('w:fldChar')
  56. toc_field.set(qn('w:fldCharType'), 'separate')
  57. r3._r.append(toc_field)
  58. # 自动生成目录内容,不包含页码
  59. for paragraph in doc.paragraphs:
  60. if 'Heading' in paragraph.style.name:
  61. b = paragraph._element.findall('.//' + qn('w:bookmarkStart'))
  62. bookmark_name = b[0].get(qn('w:name'))
  63. text = paragraph.text
  64. level = int(paragraph.style.name[-1])
  65. # print(text, bookmark_name)
  66. toc_paragraph = catalog_p.insert_paragraph_before(style='Normal')
  67. # 二级标题设置缩进
  68. if level == 2:
  69. toc_paragraph.paragraph_format.first_line_indent = Pt(24)
  70. # 设置制表符,可显示页码前的"…………"
  71. tabs = OxmlElement('w:tabs')
  72. tab1 = OxmlElement('w:tab')
  73. tab1.set(qn('w:val'), "left")
  74. tab1.set(qn('w:leader'), "dot")
  75. tab1.set(qn('w:pos'), "8400")
  76. tabs.append(tab1)
  77. toc_paragraph._p.pPr.append(tabs)
  78. # toc_paragraph若未设定style,toc_paragraph._p没有pPr属性,需注释前一句代码,使用以下语句
  79. # pPr = OxmlElement('w:pPr')
  80. # pPr.append(tabs)
  81. # toc_paragraph._p.append(pPr)
  82. hyperlink = OxmlElement('w:hyperlink')
  83. hyperlink.set(qn('w:anchor'), bookmark_name)
  84. hyperlink.set(qn('w:history'), '1')
  85. hr1 = OxmlElement('w:r')
  86. rPr = OxmlElement('w:rPr')
  87. rStyle = OxmlElement('w:rStyle')
  88. rStyle.set(qn('w:val'), "a4")
  89. rPr.append(rStyle)
  90. hr1.text = text
  91. hr1.append(rPr)
  92. hyperlink.append(hr1)
  93. hr2 = OxmlElement('w:r')
  94. rPr = OxmlElement('w:rPr')
  95. fldChar = OxmlElement('w:fldChar')
  96. fldChar.set(qn('w:fldCharType'), 'begin')
  97. hr2.append(rPr)
  98. hr2.append(fldChar)
  99. hyperlink.append(hr2)
  100. hr3 = OxmlElement('w:r')
  101. rPr = OxmlElement('w:rPr')
  102. instrText = OxmlElement('w:instrText')
  103. instrText.set(qn('xml:space'), 'preserve')
  104. instrText.text = ' PAGEREF {} \h '.format(bookmark_name)
  105. hr3.append(rPr)
  106. hr3.append(instrText)
  107. hyperlink.append(hr3)
  108. hr4 = OxmlElement('w:r')
  109. rPr = OxmlElement('w:rPr')
  110. fldChar = OxmlElement('w:fldChar')
  111. fldChar.set(qn('w:fldCharType'), 'separate')
  112. hr4.append(rPr)
  113. hr4.append(fldChar)
  114. hyperlink.append(hr4)
  115. hrt = OxmlElement('w:r')
  116. tab = OxmlElement('w:tab')
  117. hrt.append(tab)
  118. hyperlink.append(hrt)
  119. hr5 = OxmlElement('w:r')
  120. rPr = OxmlElement('w:rPr')
  121. hr5.text = ''
  122. hr5.append(rPr)
  123. hyperlink.append(hr5)
  124. hr6 = OxmlElement('w:r')
  125. rPr = OxmlElement('w:rPr')
  126. fldChar = OxmlElement('w:fldChar')
  127. fldChar.set(qn('w:fldCharType'), 'end')
  128. hr6.append(rPr)
  129. hr6.append(fldChar)
  130. hyperlink.append(hr6)
  131. toc_paragraph._p.append(hyperlink)
  132. # 目录结尾的值域
  133. toc_paragraph = catalog_p.insert_paragraph_before()
  134. r4 = toc_paragraph.add_run()
  135. toc_field = OxmlElement('w:fldChar')
  136. toc_field.set(qn('w:fldCharType'), 'end')
  137. r4._r.append(toc_field)
  138. # 分页
  139. break_page_p = catalog_p.insert_paragraph_before()
  140. break_page_p.add_run().add_break(WD_BREAK.PAGE)
  141. doc.save(r'result.docx')