实战环境:华为云 FlexusX ECS | Ubuntu 24.04.4 | Python 3.12.3
核心库:python-docx 1.1.2 + openpyxl 3.1.5 + Pillow
涉及实验:Word 20个 + Excel 4个 = 24个实验,全部上机跑通

写在前面

还在手动写周报、做报表、批量生成合同?Python 两大 Office 库——python-docxopenpyxl——让你彻底告别重复劳动。

本文从零搭建环境,24 个实验逐行跑通 Word 文档生成与 Excel 电子表格处理的全流程。所有代码均可直接复制使用。

环境搭建

# 安装依赖 (Ubuntu 24.04 需 --break-system-packages 跳过 PEP 668)
pip3 install python-docx openpyxl Pillow --break-system-packages \
  -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com

验证安装:

>>> from docx import Document
>>> import openpyxl
>>> openpyxl.__version__
'3.1.5'

第一篇:Word 文档 (python-docx)

1.1 核心架构速览

┌─────────────────────────────────────────────────────┐
│                    Document                          │
│                      │                               │
│         ┌────────────┼────────────┐                  │
│         ▼            ▼            ▼                  │
│    paragraphs    tables      sections                │
│         │                                │           │
│         ▼                                ▼           │
│      Run                          Header/Footer      │
│    (最小格式单元)                    (页眉/页脚)        │
│                                                      │
│    docx 本质 = ZIP 包 { XML + media }                │
│    word/document.xml  <- 核心内容文件                  │
└─────────────────────────────────────────────────────┘

1.2 基础操作:创建文档、段落、标题

实验1-3:创建文档 → 添加段落 → 标题分级 → 分页

from docx import Document

doc = Document()

# 标题 (level 1~9)
doc.add_heading("一级标题 Heading 1", level=1)
doc.add_heading("二级标题 Heading 2", level=2)

# 普通段落
p = doc.add_paragraph("这是一个普通段落。")
p.add_run(" 同一段落内的 Run 文字。")  # Run = 行内文字元素

# 换行符
p2 = doc.add_paragraph("第一行。")
p2.add_run("\n第二行(用 \\n 换行)。")

# 分页
doc.add_page_break()
doc.add_paragraph("新页面内容。")

doc.save("output.docx")

踩坑提示add_run("\n") 是软换行(Line Break),不会产生新段落。Word 中 Shift+Enter 对应 run 中的 \n,Enter 对应新 paragraph。

1.3 表格操作:创建、合并、增加行列

实验4-5:表格全生命周期

from docx import Document

doc = Document()
doc.add_heading("Python 数据类型对比表", level=1)

# 创建 5行×4列 表格
table = doc.add_table(rows=5, cols=4)
table.style = 'Light Grid Accent 1'

# 表头
headers = ['类型名称', '英文名称', '可变性', '示例']
for i, h in enumerate(headers):
    table.rows[0].cells[i].text = h

# 数据行
data = [
    ['整数',   'int',   '不可变', '42'],
    ['字符串', 'str',   '不可变', '"hello"'],
    ['列表',   'list',  '可变',   '[1, 2, 3]'],
    ['字典',   'dict',  '可变',   '{"a": 1}'],
]
for row_idx, row_data in enumerate(data, 1):
    for col_idx, val in enumerate(row_data):
        table.rows[row_idx].cells[col_idx].text = val

# === 表格高级操作 ===
t2 = doc.add_table(rows=3, cols=3)
# 合并单元格
t2.cell(0, 0).merge(t2.cell(0, 2))
t2.cell(0, 0).text = "合并了 (0,0)~(0,2)"

# 新增行
row_new = t2.add_row()
for j in range(3):
    row_new.cells[j].text = f"新增列{j}"

doc.save("table_demo.docx")

真实服务器输出

行数: 4, 列数: 3

表格样式速查(内置63种)

类别 样式名示例 效果
浅色网格 Light Grid Accent 1~6 浅色表头+边框
中等底纹 Medium Shading 1 Accent 1~6 隔行变色
列表样式 Light List Accent 1~6 无网格线
彩色 Colorful Grid/List/Shading 多彩表头

1.4 Run:最小格式单元

实验7-8:bold / italic / underline / strike / 字号 / 颜色

p = doc.add_paragraph()
p.add_run("正常文字。")
p.add_run("粗体文字").bold = True
p.add_run("斜体文字").italic = True

run = p.add_run("粗斜体下划线删除线")
run.bold = True
run.italic = True
run.underline = True
run.font.strike = True   # 删除线

# 多级字号
sizes = [8, 10, 12, 14, 18, 24, 36, 48]
for sz in sizes:
    run = p.add_run(f"{sz}pt ")
    run.font.size = Pt(sz)
    run.font.color.rgb = RGBColor(0, 51, 102)

Run 属性总表

属性 类型 示例
run.bold bool True
run.italic bool True
run.underline bool/str True / 'single' / 'double'
run.font.strike bool True = 删除线
run.font.size Pt Pt(12)
run.font.color.rgb RGBColor RGBColor(0xFF, 0, 0)
run.font.name str '宋体'

1.5 样式系统:内置样式 + 修改 + 应用

实验6:36种内置段落样式

from docx.enum.style import WD_STYLE_TYPE

# 查看所有段落样式
styles = [s.name for s in doc.styles if s.type == WD_STYLE_TYPE.PARAGRAPH]
# ['Normal', 'Header', 'Footer', 'Heading 1'~'Heading 9', 
#  'Title', 'Subtitle', 'Quote', 'Intense Quote', 
#  'List Bullet', 'List Number', ...]

# 应用样式
doc.add_paragraph("这是引用样式", style='Quote')
doc.add_paragraph("这是列表项", style='List Bullet')

# 修改默认样式
style = doc.styles['Normal']
style.font.size = Pt(11)
style.font.name = 'Times New Roman'

1.6 文档属性与批量生成

实验9:设置元数据 + 循环生成多份文档

import datetime

# 设置核心属性 (Word 文件→右键→属性可见)
doc.core_properties.title = "Python办公自动化示例"
doc.core_properties.author = "Python Learner"
doc.core_properties.subject = "python-docx实战"
doc.core_properties.created = datetime.datetime.now()

# 批量生成:4人入职通知书
users = ["张三", "李四", "王五", "赵六"]
for user in users:
    doc = Document()
    doc.add_heading(f"{user} 的入职通知书", level=1)
    doc.add_paragraph(f"尊敬的{user}:")
    doc.add_paragraph("    恭喜您通过面试!请于2026年8月1日报到。")
    doc.save(f"入职通知_{user}.docx")

服务器实测:4份文档瞬间生成,每份 ~36KB。

1.7 计量单位:Pt / Emu / Twips

实验10-11:理解 docx 内部坐标系统

from docx.shared import Pt, Cm, Inches, Emu

# 实测输出
1 pt   = 12700 EMU
1 cm   = 360000 EMU
1 inch = 914400 EMU
换算关系:
  1 inch  = 72 pt  = 2.54 cm
  1 pt    = 12700 EMU  (English Metric Unit)
  1 cm    = 360000 EMU  = 567 twips
  1 twip  = 635 EMU     (1/20 pt, "二十分之一点")

EMU (English Metric Unit) 是 OOXML 标准的基础长度单位,确保整数运算无精度损失。

1.8 字体颜色:RGB 真彩色

实验12:8种颜色演示

from docx.shared import RGBColor

colors = [
    ("红色", 0xFF, 0x00, 0x00),
    ("绿色", 0x00, 0x80, 0x00),
    ("蓝色", 0x00, 0x00, 0xFF),
    ("橙色", 0xFF, 0xA5, 0x00),
    ("紫色", 0x80, 0x00, 0x80),
]

for name, r, g, b in colors:
    run = p.add_run(f"[{name}] ")
    run.font.color.rgb = RGBColor(r, g, b)

1.9 中文字体:关键坑点

实验13:中文字体必须同时设置西文 + 东亚字体

from docx.oxml.ns import qn

run = p.add_run("这是宋体中文")
run.font.name = '宋体'
# ★ 关键:必须设置 eastAsia 属性,否则中文可能不生效
run._element.rPr.rFonts.set(qn('w:eastAsia'), '宋体')

docx 本质:ZIP 包结构

用 Python 解压查看 docx 内部:

[Content_Types].xml          ← 内容类型清单
docProps/core.xml             ← 文档属性(作者/日期)
docProps/app.xml              ← 应用属性(页数/字数)
word/document.xml             ← ★ 核心:文档正文 XML
word/styles.xml               ← 样式定义
word/fontTable.xml            ← 字体表
word/media/                   ← 图片等媒体资源
word/theme/theme1.xml         ← 主题定义

document.xml 片段预览:2319 字节的 XML,包含所有段落、表格、样式引用。

1.10 段落间距与行间距

实验14:段前/段后间距 + 行距对比

from docx.shared import Pt

# 段间距
p = doc.add_paragraph("段前6pt, 段后6pt")
p.paragraph_format.space_before = Pt(6)
p.paragraph_format.space_after = Pt(6)

# 行间距
p.paragraph_format.line_spacing = 1.5     # 1.5倍行距
p.paragraph_format.line_spacing = Pt(24)  # 固定24pt
行距类型 设置方式 效果
单倍 1.0 默认
1.5倍 1.5 常用
双倍 2.0 论文要求
固定值 Pt(24) 精确控制
最小值 需用 XML 操作 w:lineRule="atLeast"

1.11 页面设置:A4 + 横竖版混排

实验15-16:分节符实现同一文档内横竖版切换

from docx.shared import Cm
from docx.enum.section import WD_ORIENT

# 默认页面尺寸 (Letter: 21.59cm × 27.94cm)
section = doc.sections[0]
# width=7772400 EMU (≈21.59cm), height=10058400 EMU (≈27.94cm)

# 设为 A4
section.page_width = Cm(21)
section.page_height = Cm(29.7)
section.top_margin = Cm(2.54)
section.bottom_margin = Cm(2.54)
section.left_margin = Cm(3.18)
section.right_margin = Cm(3.18)

# 添加分节符 → 横版
doc.add_section()
sec2 = doc.sections[1]
sec2.orientation = WD_ORIENT.LANDSCAPE
sec2.page_width = Cm(29.7)   # 宽
sec2.page_height = Cm(21)    # 高

常用纸张尺寸

纸张 宽(cm) 高(cm) 宽(EMU) 高(EMU)
A4 21.0 29.7 7560310 10692130
A3 29.7 42.0 ~ ~
Letter 21.59 27.94 7772400 10058400
B5 17.6 25.0 ~ ~

1.12 页脚 + 域(Field):自动页码

实验17:PAGE / NUMPAGES 域实现"第X页/共Y页"

from docx.oxml import OxmlElement
from docx.oxml.ns import qn

footer = doc.sections[0].footer
p = footer.paragraphs[0]
p.text = "第 "

# 插入 PAGE 域
run = p.add_run()
fldChar = OxmlElement('w:fldChar')
fldChar.set(qn('w:fldCharType'), 'begin')
run._r.append(fldChar)

run2 = p.add_run()
instrText = OxmlElement('w:instrText')
instrText.set(qn('xml:space'), 'preserve')
instrText.text = ' PAGE '
run2._r.append(instrText)

run3 = p.add_run()
fldChar2 = OxmlElement('w:fldChar')
fldChar2.set(qn('w:fldCharType'), 'end')
run3._r.append(fldChar2)

p.add_run(" 页 / 共 ")

# ... 同样方式插入 NUMPAGES 域 ...
p.add_run(" 页")
p.alignment = WD_ALIGN_PARAGRAPH.CENTER

常用域代码

域代码 功能 用法
PAGE 当前页码 { PAGE }
NUMPAGES 总页数 { NUMPAGES }
DATE 当前日期 { DATE }
TOC 自动目录 { TOC \o "1-3" }
HYPERLINK 超链接 需特殊构造

1.13 页眉 + 目录(TOC)

实验18:页眉 + TOC 域

# 页眉
header = doc.sections[0].header
header.paragraphs[0].text = "Python-docx 实战手册"
header.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER

# TOC 域 (提取 Heading 1~3)
# 在 Word 中打开后右键 → 更新域 生效
p = doc.add_paragraph()
run = p.add_run()
# 插入 TOC \o "1-3" \h \z \u 域代码

踩坑:python-docx 只能写入 TOC 域代码,实际目录内容需要 Word 打开后"更新域"才能渲染。

1.14 完整 Demo:列表 + 图片 + 综合表格

实验19-20:集成所有功能

from docx.shared import Inches

# 无序列表
for item in ["Python程序设计", "数据结构与算法"]:
    doc.add_paragraph(item, style='List Bullet')

# 有序列表
for item in ["需求分析", "系统设计", "编码实现", "测试部署"]:
    doc.add_paragraph(item, style='List Number')

# 插入图片
from PIL import Image
img = Image.new('RGB', (400, 200), color=(70, 130, 180))
img.save("test.png")
doc.add_picture("test.png", width=Inches(3))

# 提取文档中的图片 (docx本质是ZIP)
import zipfile
with zipfile.ZipFile("doc_with_images.docx", 'r') as z:
    for name in z.namelist():
        if 'media' in name:
            z.extract(name, "extracted/")  # 1张图片已提取

第二篇:Excel 电子表格 (openpyxl)

2.1 核心架构速览

┌─────────────────────────────────────────────────┐
│                 Workbook (工作簿)                 │
│                      │                           │
│     ┌────────────────┼────────────────┐          │
│     ▼                ▼                ▼          │
│  Worksheet       Worksheet        Worksheet      │
│  (Q1季度)        (Q2季度)         (Q3季度)       │
│     │                                               │
│     ├── Cell (单元格: A1, B2, ...)                  │
│     ├── Row / Column 操作                           │
│     ├── Styles (Font/Fill/Border/Alignment)         │
│     ├── Protection (工作表/工作簿保护)                │
│     └── Properties (标签颜色/显示比例)                │
└─────────────────────────────────────────────────┘

2.2 基础工作流:读/写/公式

实验1:创建工作簿 → 写入数据 → 公式 → 回读验证

from openpyxl import Workbook

wb = Workbook()
ws = wb.active
ws.title = "数据表"

# 写入表头
ws['A1'] = '姓名'
ws['B1'] = '年龄'
ws['C1'] = '城市'
ws['D1'] = '薪资'

# 写入数据 (行列索引从1开始)
employees = [
    ['张三', 28, '深圳', 15000],
    ['李四', 32, '北京', 22000],
    ['王五', 25, '上海', 18000],
    ['赵六', 30, '广州', 20000],
    ['孙七', 27, '杭州', 17000],
]
for i, row in enumerate(employees, 2):
    for j, val in enumerate(row):
        ws.cell(row=i, column=j+1, value=val)

# 公式
ws['D7'] = '=AVERAGE(D2:D6)'
ws['C7'] = '平均薪资'

wb.save("basic.xlsx")

# 回读验证
wb2 = openpyxl.load_workbook("basic.xlsx")
ws2 = wb2.active
for row in ws2.iter_rows(min_row=1, max_row=7, values_only=True):
    print(row)

服务器实测输出

('姓名', '年龄', '城市', '薪资')
('张三', 28, '深圳', 15000)
('李四', 32, '北京', 22000)
('王五', 25, '上海', 18000)
('赵六', 30, '广州', 20000)
('孙七', 27, '杭州', 17000)
(None, None, '平均薪资', '=AVERAGE(D2:D6)')

2.3 工作表操作:CRUD + 移动 + 复制

实验2:多工作表全生命周期

wb = Workbook()

# 批量创建
for name in ['Q1季度', 'Q2季度', 'Q3季度', 'Q4季度']:
    wb.create_sheet(name)

del wb['Sheet']                          # 删除默认 Sheet
print(wb.sheetnames)
# ['Q1季度', 'Q2季度', 'Q3季度', 'Q4季度']

# 复制
wb.copy_worksheet(wb['Q1季度'])
wb['Q1季度 Copy'].title = 'Q1季度备份'
# ['Q1季度', 'Q2季度', 'Q3季度', 'Q4季度', 'Q1季度备份']

# 重命名 + 移动位置
wb['Q4季度'].title = '年报'
wb.move_sheet('年报', offset=-2)         # 前移2位
# ['Q1季度', '年报', 'Q2季度', 'Q3季度', 'Q1季度备份']

工作表操作速查

操作 方法 说明
创建 wb.create_sheet("name") 默认追加到最后
创建(指定位置) wb.create_sheet("name", 0) 插入到第1位
复制 wb.copy_worksheet(ws) 副本命名规则:原名 Copy
删除 del wb['sheetname'] 不能删除唯一工作表
移动 wb.move_sheet(ws, offset=n) n>0 后移,n<0 前移
激活 ws = wb.active 获取当前活动工作表
按索引 wb.worksheets[0] 第一个工作表

2.4 工作表属性:标签颜色 + 显示比例

实验3:彩色标签 + 缩放 + 网格线

# 标签颜色 (6位十六进制)
ws.sheet_properties.tabColor = "FF6B35"   # 橙色

colors = {
    '销量统计': '2EC4B6',   # 青色
    '客户信息': 'E71D36',   # 红色
    '库存管理': 'FF9F1C',   # 金黄
    '财务报表': '011627',   # 深蓝
}
for sname, color in colors.items():
    ws = wb.create_sheet(sname)
    ws.sheet_properties.tabColor = color

# 显示设置
ws.sheet_view.zoomScale = 120             # 120% 缩放
ws.sheet_view.showGridLines = True        # 显示网格线
# ws.sheet_view.showGridLines = False     # 隐藏网格线

# 冻结窗格
ws.freeze_panes = 'A2'                    # 冻结首行
# ws.freeze_panes = 'B2'                  # 冻结首行+首列

# 自动筛选
ws.auto_filter.ref = "A1:F6"

2.5 样式综合演示

内嵌实战:企业级员工信息表

from openpyxl.styles import Font, PatternFill, Alignment, Border, Side

# 表头样式
header_font = Font(name='微软雅黑', size=11, bold=True, color='FFFFFF')
header_fill = PatternFill(start_color='4472C4', end_color='4472C4', fill_type='solid')

# 数据区样式
thin_border = Border(
    left=Side(style='thin'), right=Side(style='thin'),
    top=Side(style='thin'), bottom=Side(style='thin'),
)

# 隔行变色 + 状态列条件着色
for r_idx, row_data in enumerate(staff, 2):
    for c_idx, val in enumerate(row_data):
        cell = ws.cell(row=r_idx, column=c_idx, value=val)
        cell.border = thin_border
        cell.alignment = Alignment(horizontal='center', vertical='center')

        if r_idx % 2 == 0:   # 偶数行浅蓝背景
            cell.fill = PatternFill(start_color='D9E2F3', end_color='D9E2F3', fill_type='solid')

        if c_idx == 6:       # 状态列
            if val == '在职':
                cell.font = Font(color='006100')
                cell.fill = PatternFill(start_color='C6EFCE', end_color='C6EFCE', fill_type='solid')
            else:
                cell.font = Font(color='9C0006')
                cell.fill = PatternFill(start_color='FFC7CE', end_color='FFC7CE', fill_type='solid')

openpyxl 样式组件

组件 常用参数
字体 Font name, size, bold, italic, color, underline
填充 PatternFill start_color, end_color, fill_type='solid'
边框 Border + Side left, right, top, bottom (Side(style='thin'))
对齐 Alignment horizontal, vertical, wrap_text, text_rotation
数字格式 cell.number_format '#,##0.00', 'yyyy-mm-dd', '0%'

2.6 保护工作表/工作簿

实验4:密码保护 + 锁定结构

# ===== 工作表保护 =====
ws.protection.sheet = True
ws.protection.password = '123456'
ws.protection.set_password('123456')

# 允许特定操作
ws.protection.selectLockedCells = True
ws.protection.selectUnlockedCells = True
# ws.protection.formatCells = False      # 禁止格式化
# ws.protection.insertRows = False       # 禁止插入行

# ===== 工作簿保护 =====
wb.security.workbookPassword = 'admin123'
wb.security.set_workbook_password('admin123')
wb.security.lockStructure = True          # 锁定结构(禁止增删工作表)

2.7 性能测试

实验附加:100行×10列读写性能

写入耗时: 0.0023s
保存耗时: 0.0071s
读取耗时: 0.0102s (只读模式, 共100行)

大文件优化建议

场景 方法 效果
只读 load_workbook(read_only=True) 内存占用↓90%
只写 Workbook(write_only=True) 适合百万级数据导出
批量写 ws.append() 代替逐个 cell() 速度↑3~5x
数据纯读取 iter_rows(values_only=True) 跳过样式对象

踩坑记录

坑1:中文字体不生效

run.font.name = '宋体'           # 仅设置西文字体,中文不生效
run._element.rPr.rFonts.set(
    qn('w:eastAsia'), '宋体')    # ★ 必须同时设置东亚字体

坑2:PEP 668 pip 安装限制

error: externally-managed-environment
解决: pip3 install xxx --break-system-packages

坑3:华为云香港 PyPI 超时

Timeout connecting to pypi.org
解决: -i https://mirrors.aliyun.com/pypi/simple/

坑4:TOC 目录不显示

python-docx 只能写入 TOC 域代码
必须用 Word 打开 → 右键"更新域" 才能渲染

坑5:单元格坐标从 1 开始

ws.cell(row=1, column=1)  # 对应 Excel 的 A1
# 与 Python 列表索引从 0 开始的习惯不同!

坑6:del wb['Sheet']删除唯一工作表报错

openpyxl 要求工作簿至少保留 1 个工作表
先创建新工作表再删除默认的

实战文件清单

Word 产出 (19个文件)

文件 大小 对应实验
exp01_new.docx 36KB 实验1-2:创建+读取
exp03_headings.docx 36KB 实验3:标题/段落/分页
exp04_table.docx 37KB 实验4-5:表格/合并
exp06_styles.docx 36KB 实验6:样式系统
exp07_run.docx 36KB 实验7-8:Run格式
exp09_props.docx 36KB 实验9:文档属性
batch_张三~赵六.docx 4×36KB 实验9:批量生成
exp12_colors.docx 36KB 实验12:RGB颜色
exp13_fonts.docx 36KB 实验13:中文字体
exp14_spacing.docx 36KB 实验14:段落间距
exp15_page.docx 36KB 实验15-16:页面设置
exp17_footer.docx 37KB 实验17:页脚+域
exp18_toc.docx 37KB 实验18:页眉+TOC
exp19_demo.docx 38KB 实验19-20:完整demo

Excel 产出 (7个文件)

文件 大小 对应实验
exp01_basic.xlsx 5.1KB 实验1:基础读写
exp02_sheets.xlsx 7.4KB 实验2:工作表CRUD
exp03_props.xlsx 7.0KB 实验3:标签颜色/缩放
exp04_protect_sheet.xlsx 5.1KB 实验4:工作表保护
exp04_protect_workbook.xlsx 4.9KB 实验4:工作簿保护
exp_style_demo.xlsx 6.3KB 综合样式演示
exp_big.xlsx 8.6KB 性能测试

总结

维度 python-docx openpyxl
目标格式 .docx (Word) .xlsx (Excel)
核心概念 Document → Paragraph → Run Workbook → Worksheet → Cell
样式方式 内置样式 + Run属性 Font/Fill/Border/Alignment 对象
复杂操作 域(Field)、分节符(Section) 公式、图表、数据透 视表
内部结构 ZIP(XML) 透明可见 ZIP(XML) 透明可见
扩展能力 图片/表格/页眉页脚 条件格式/数据验证/命名范围
性能上限 百页级文档 百万行级(只读/只写模式)
学习曲线 ★★★☆☆ (Run概念需理解) ★★☆☆☆ (直觉型)

再也不用手动写周报、做报表、生成合同了。Python 两行代码启动,剩下的事交给循环。

觉得上面的内容有用吗?快来点个赞吧!

点赞() 我要打赏

温馨提示 : 本站内容来自会员投稿以及互联网,所有源码及教程均为作者总结编辑,请大家在使用过程中提前做好备份,以免发生无法预知的错误,源码类教程请勿直接用于生产环境!

 可能感兴趣的文章

1 2 3 4 5