python操作word全

发布时间 2023-09-12 00:18:08作者: 菩提浪子
由于最近有任务需要自动生成word报告,因此学习了一些python-docx的使用方法,在此总结。

目前网上相关的资料不算太多,且大多数都很简单。有一些稍微复杂的需求往往找不到答案,很多想要的方法这个库似乎并没有直接提供。在git上看,这个包最新的一次更新是2021年。希望有大神能接过这个接力棒,继续维护更新。

一、基础内容
1、document对象
整个操作过程实际就是围绕着document对象进行“增删改查”。因此,首先需要创建一个文档对象

# pip install python-docx
from docx import Document
document = Document()
上述操作会创建一个新的空白文档,如果我们想打开已有的模板文档,只需指定其路径即可

document = Document('配置/基础模板.docx')
当所有的操作完成后我们需要保存文档

document.save(os.path.join(os.getcwd(), 'xx报告.docx'))
2、插入标题
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT

# 添加一个二级标题
head = document.add_heading(level=2)
# 标题居中
head.alignment = WD_PARAGRAPH_ALIGNMENT.CENTER
# 标题的内容
run = head.add_run('绿水青山就是金山银山')
# 字体
run.font.name = 'Times New Roman'
3、插入一个段落
from docx.shared import Pt

# 先获得段落对象
p = document.add_paragraph()
# 首行缩进20磅
p.paragraph_format.first_line_indent = Pt(20)
# 设置段落格式
fmt = p.paragraph_format
# 设置行间距
fmt.line_spacing = 1.5
# 一个段落可以有多个run对象,主要考虑同一段落的文字可能有多种样式
run = p.add_run('段落内容1')
这个run对象,一开始我也没太理解。已经添加了一个段落对象,直接填充段落内容不就行了嘛。段落对象下面再添加一个run对象是什么意思?原来这个run对象就是一段文本整体,这样你可以对这个整体进行统一样式设置。没有run对象的话,你就只能对段落对象进行统一设置,那就无法实现下面的效果



对一个run对象设置字体、颜色、大小等方法如下

from docx.shared import RGBColor

# 设置字体
run.font.name = 'Times New Roman'
# 字体大小
run.font.size = Pt(20)
# 字体颜色
run.font.color.rgb = RGBColor(255, 0, 0)
# 加粗
run.font.bold = True
# 斜体
run.font.italic = True

我们一般习惯使用“小四”、“五号”来表示字体大小,但在程序里只支持传入磅值,下面是字号和磅值的对应关系。

字号和磅值对应关系
字号 磅值 字号 磅值
八号 5 小三 15
七号 5.5三号 16
小六 6.5小二 18
六号 7.5二号 22
小五 9 小一 24
五号 10.5一号 26
小四 12 小初 36
四号 14 初号 42
4、插入一个表格
添加表格一般有两种情况。第一种是创建表格时就明确行和列的数量,然后循环往里添加内容

arr = np.array([['A', '001'], ['B', '002'], ['C', '003']])
# 如果要加表头,rows=4,表格预定义样式详见官网
table = document.add_table(rows=3, cols=2, style='Colorful List')
# 添加内容
for i, row in enumerate(table.rows):
for j, cell in enumerate(row.cells):
# 获取单元格中的段落对象
paragraph = cell.paragraphs[0]
# 和上面一样,这里的run可以设置一些属性
run = paragraph.add_run(str(arr[i, j]))


第二种情况是,提前并不确定表格的行列,需要根据数据情况临时添加。则可以先创建一个1*1的表格,然后向右增加列以及向下增加行

from docx.shared import Inches
# 自动行高,无须指定
table.add_row()
# 列宽需要指定,1英寸
table.add_column(width=Inches(1))
从上述代码可以看到,一个表格(table)对象由多个行(row)对象组成,一个行(row)对象又由多个单元格(cell)对象组成。单元格对象包含段落对象,有了段落对象我们就可以添加文字并设置样式。

5、插入图片
# 指定图片文件目录,指定插入后图片所占尺寸(会根据原始尺寸和指定尺寸自动缩放)
document.add_picture('xx.png', width=Pt(500), height=Pt(400))
6、插入页眉
from docx.shared import Cm
section = document.sections[0]
header = section.header
paragraph = header.paragraphs[0]
# 也可以直接插入文字
run = paragraph.add_run()
# 这里是插入logo图片
run.add_picture("logo.png", height=Cm(0.91))
二、常见问题
1、如何指定中文字体
前面我们指定的字体是新罗马体,没什么问题。但如果我们直接将其改为'宋体'或'Sim Sun',都不会生效。这是因为宋体是非西文字体,默认是西文字体,因此不识别。需要如下操作

from docx.oxml.ns import qn
run.font.name = '宋体'
# 设置东亚字体
run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')
2、如何自定义样式
一份文档中,标题、正文、表格内容样式基本是统一的。因此,可以预先自定义一些样式,并命名。后续即可直接通过名称应用这些样式,而不用每次都去定义。有点像格式刷的效果。

from docx.enum.style import WD_STYLE_TYPE

style = document.styles.add_style('my_style', WD_STYLE_TYPE.CHARACTER)
style.font.color.rgb = RGBColor(255, 0, 0)
style.font.name = '黑体'
style._element.rPr.rFonts.set(qn('w:eastAsia'), '黑体')
style.font.size = Pt(20)
style.font.bold = True

run1 = p.add_run('社会主义核心价值观是社会主义核心价值体系的内核')
run2 = p.add_run('比心')
# 将自定义的样式应用在run2上
run2.style = 'my_style'
run3 = p.add_run('体现社会主义核心价值体系的根本性质和基本特征')


3、如何替换模板文档中文字
如果我们想基于一个模板文档进行二次编辑,可以在模板文档中设置一些占位。通过替换占位达到编辑的目的。如果是替换表格内容,可遍历单元格cell,通过对cell.text重新赋值即可。

for p in document.paragraphs:
if p.text == '占位1':
# 清除原有内容;也可以直接令p.text = '新的内容'
p._element.clear()
run = p.add_run('新的内容')
run.font.size = Pt(18)
使用模板文档时有一个巨坑,新建的空白文档是支持预定义的样式的,而模板文件不一定。比如你在创建表格时指定style='Colorful List',实际并不一定会生效。具体原因目前还没搞清楚。具体模板文件有哪些预定义的样式,可以通过下述方法获知。

for style in document.styles:
print(style.name)
预定义的样式可查看官网,下面是部分截图



4、如何合并多个文档
new_doc = Document()

# 以此类推,将多个文档(doc2,doc3)的内容添加进去
for elem in document1.element.body:
new_doc.element.body.append(elem)
但这种方法有一个缺点,无法复制图片。下面提供一种不使用python-docx但有效的方法。

from win32com.client import Dispatch

cwd = os.getcwd()
word = Dispatch('Word.Application')
doc_files = word.Documents.Add()
# 插入文档
doc_files.Application.Selection.Range.InsertFile(os.path.join(cwd, 'tmp1.docx'))
doc_files.Application.Selection.Range.InsertFile(os.path.join(cwd, 'tmp2.docx'))
doc_files.SaveAs(os.path.join(cwd, '合并.docx'))
# 一定要关闭
word.Quit()

示例二
import docx
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_CELL_VERTICAL_ALIGNMENT
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT
from docx.shared import Pt, Inches
from page_num import add_page_number

# 1.创建docx对象
document = docx.Document()

# 设置页眉
run_header = document.sections[0].header.paragraphs[0].add_run("test")
document.sections[0].header.paragraphs[0].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER # 居中对齐
print(len(document.sections))

# 2.添加标题
"""
add_heading():建立标题
- document.add_heading('content_of_heading', level=n)
"""
document.add_heading('侠客行', level=1) # 标题1格式
document.add_heading('李白', level=2) # 标题2格式

# 3.添加段落
# 创建段落对象
"""
add_paragraph():建立段落Paragraph内容
- document.add_paragraph('paragraph_content')
"""
paragraph_object = document.add_paragraph('赵客缦胡缨,吴钩霜雪明。')
document.add_paragraph('银鞍照白马,飒沓如流星。')
document.add_paragraph('十步杀一人,千里不留行。')
document.add_paragraph('事了拂衣去,深藏身与名。')
document.add_paragraph('闲过信陵饮,脱剑膝前横。')
document.add_paragraph('将炙啖朱亥,持觞劝侯嬴。')
document.add_paragraph('三杯吐然诺,五岳倒为轻。')
document.add_paragraph('眼花耳热后,意气素霓生。')
document.add_paragraph('救赵挥金槌,邯郸先震惊。')
document.add_paragraph('千秋二壮士,烜赫大梁城。')
document.add_paragraph('纵死侠骨香,不惭世上英。')
document.add_paragraph('谁能书阁下,白首太玄经。')
prior_paragraph_object = paragraph_object.insert_paragraph_before('') # 在paragraph前插入新段落
# 4.建立Run内容
"""
Paragraph是由Run组成,使用add_run()方法可以在Paragraph中插入内容,语法如下:
paragraph_object.add_run('run_content')
"""
run1 = prior_paragraph_object.add_run('*'*13)
run2 = prior_paragraph_object.add_run('%'*13)
# 设置Run的样式
"""
bold: 加粗
italic:斜体
underline:下划线
strike:删除线
"""
run1.bold = True
run2.underline = True

# 设置段落居中对齐
for i in range(len(document.paragraphs)):
document.paragraphs[i].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER # 居中对齐

# 5.添加换页符
# add_page_break()
document.add_page_break()
# print(len(document.paragraphs))
# 6.插入图片
# add_picture(),调整图片宽高需导入docx.shared模块
document.add_picture('libai.jpeg', width=Pt(200), height=Pt(300))

# 设置居中对齐
document.paragraphs[len(document.paragraphs)-1].alignment = WD_PARAGRAPH_ALIGNMENT.CENTER # 居中对齐

# 7.创建表格
"""
add_table(rows=n, cols=m)
"""
table = document.add_table(rows=2, cols=5)
# 添加表格内容
# 添加第1行数据
row = table.rows[0]
row.cells[0].text = '姓名'
row.cells[1].text = '字'
row.cells[2].text = '号'
row.cells[3].text = '所处时代'
row.cells[4].text = '别称'
# 添加第2行数据
row = table.rows[1]
row.cells[0].text = '李白'
row.cells[1].text = '太白'
row.cells[2].text = '青莲居士'
row.cells[3].text = '唐朝'
row.cells[4].text = '诗仙'

# 插入行
new_row = table.add_row() # 增加表格行
new_row.cells[0].text = '白居易'
new_row.cells[1].text = '乐天'
new_row.cells[2].text = '香山居士'
new_row.cells[3].text = '唐朝'
new_row.cells[4].text = '诗魔'

# 插入列
new_column = table.add_column(width=Inches(1)) # 增加表格列
new_column.cells[0].text = '代表作'
new_column.cells[1].text = '《侠客行》、《静夜思》'
new_column.cells[2].text = '《长恨歌》、《琵琶行》'

# 计算表格的rows和cols的长度
rows = len(table.rows)
cols = len(table.columns)
print(f'rows: {rows}')
print(f'columns: {cols}')

# 打印表格内容
# for row in table.rows:
# for cell in row.cells:
# print(cell.text)

# 设置表格样式
# table.style = 'LightShading-Accent1'
# UserWarning: style lookup by style_id is deprecated. Use style name as key instead.
table.style = 'Light Shading Accent 1'
# 循环将每一行,每一列都设置为居中
for r in range(rows):
for c in range(cols):
table.cell(r, c).vertical_alignment = WD_CELL_VERTICAL_ALIGNMENT.CENTER # 垂直居中
table.cell(r, c).paragraphs[0].paragraph_format.alignment = WD_TABLE_ALIGNMENT.CENTER # 水平居中

# 设置页码
add_page_number(document.sections[0].footer.paragraphs[0])
# 保存文件
document.save('test2.docx')