Python操作PPT:python-pptx批量生成幻灯片,数据驱动的演示文稿
PowerPoint是制作演示文稿的常用工具。python-pptx库可以创建、读取和修改PPT文件,实现报告自动生成、模板填充等任务。本篇将介绍如何使用Python自动化PPT操作。
1. python-pptx简介
pip install python-pptx
from pptx import Presentation
from pptx.util import Inches, Pt, Cm, Emu
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.chart import XL_CHART_TYPE
# 单位说明
# Inches:英寸
# Pt:磅
# Cm:厘米
# Emu:英制公制单位
2. 创建PPT
from pptx import Presentation
from pptx.util import Inches, Pt
# 创建演示文稿
prs = Presentation()
# 设置幻灯片大小(默认是4:3)
prs.slide_width = Inches(13.333) # 16:9宽度
prs.slide_height = Inches(7.5) # 16:9高度
# 获取幻灯片布局
# 0: 标题幻灯片
# 1: 标题和内容
# 2: 节标题
# 3: 两栏内容
# 4: 比较
# 5: 仅标题
# 6: 空白
# 7: 内容与标题
# 8: 图片与标题
# 添加标题幻灯片
title_slide_layout = prs.slide_layouts[0]
slide = prs.slides.add_slide(title_slide_layout)
# 设置标题和副标题
title = slide.shapes.title
subtitle = slide.placeholders[1]
title.text = "演示文稿标题"
subtitle.text = "副标题内容\n作者:张三"
# 添加内容幻灯片
content_layout = prs.slide_layouts[1]
slide2 = prs.slides.add_slide(content_layout)
title2 = slide2.shapes.title
title2.text = "内容页标题"
body = slide2.placeholders[1]
tf = body.text_frame
tf.text = "第一个要点"
# 添加更多段落
p = tf.add_paragraph()
p.text = "第二个要点"
p.level = 0
p = tf.add_paragraph()
p.text = "子要点"
p.level = 1
# 保存
prs.save('presentation.pptx')
3. 幻灯片布局
from pptx import Presentation
# 使用模板
prs = Presentation('template.pptx')
# 查看可用布局
for i, layout in enumerate(prs.slide_layouts):
print(f"{i}: {layout.name}")
# 查看布局中的占位符
layout = prs.slide_layouts[1]
for shape in layout.placeholders:
print(f"idx: {shape.placeholder_format.idx}, type: {shape.placeholder_format.type}")
# 使用特定布局
slide = prs.slides.add_slide(prs.slide_layouts[5]) # 仅标题
# 删除幻灯片
def delete_slide(prs, index):
"""删除指定索引的幻灯片"""
rId = prs.slides._sldIdLst[index].rId
prs.part.drop_rel(rId)
del prs.slides._sldIdLst[index]
# 复制幻灯片(需要手动实现)
def duplicate_slide(prs, index):
"""复制幻灯片"""
source = prs.slides[index]
# 使用相同布局创建新幻灯片
new_slide = prs.slides.add_slide(source.slide_layout)
# 复制形状(简化版)
for shape in source.shapes:
if shape.has_text_frame:
# 复制文本框
pass
return new_slide
4. 文本操作
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6]) # 空白布局
# 添加文本框
left = Inches(1)
top = Inches(1)
width = Inches(8)
height = Inches(1)
textbox = slide.shapes.add_textbox(left, top, width, height)
tf = textbox.text_frame
# 设置文本框属性
tf.word_wrap = True # 自动换行
tf.auto_size = None # 不自动调整大小
# 添加文本
tf.text = "这是第一段文本"
# 添加更多段落
p = tf.add_paragraph()
p.text = "这是第二段文本"
# 设置段落格式
p.alignment = PP_ALIGN.CENTER # 居中
# PP_ALIGN: LEFT, CENTER, RIGHT, JUSTIFY
p.level = 0 # 缩进级别
p.space_before = Pt(12) # 段前间距
p.space_after = Pt(12) # 段后间距
# 设置字体格式
for paragraph in tf.paragraphs:
for run in paragraph.runs:
run.font.name = '微软雅黑'
run.font.size = Pt(18)
run.font.bold = True
run.font.italic = False
run.font.color.rgb = RGBColor(0, 0, 128)
# 设置文本框垂直对齐
tf.paragraphs[0].alignment = PP_ALIGN.CENTER
# 添加带格式的文本
p2 = tf.add_paragraph()
run1 = p2.add_run()
run1.text = "普通文本 "
run2 = p2.add_run()
run2.text = "粗体文本 "
run2.font.bold = True
run3 = p2.add_run()
run3.text = "红色文本"
run3.font.color.rgb = RGBColor(255, 0, 0)
prs.save('text.pptx')
5. 形状操作
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.shapes import MSO_SHAPE
from pptx.enum.text import PP_ALIGN
prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6])
# 添加矩形
shape = slide.shapes.add_shape(
MSO_SHAPE.RECTANGLE,
Inches(1), Inches(1), # 位置
Inches(3), Inches(1) # 大小
)
shape.text = "矩形"
# 设置填充颜色
fill = shape.fill
fill.solid()
fill.fore_color.rgb = RGBColor(0, 176, 240)
# 设置边框
line = shape.line
line.color.rgb = RGBColor(0, 0, 0)
line.width = Pt(2)
# 添加圆角矩形
shape2 = slide.shapes.add_shape(
MSO_SHAPE.ROUNDED_RECTANGLE,
Inches(5), Inches(1),
Inches(3), Inches(1)
)
shape2.text = "圆角矩形"
# 添加椭圆
shape3 = slide.shapes.add_shape(
MSO_SHAPE.OVAL,
Inches(1), Inches(3),
Inches(2), Inches(2)
)
shape3.text = "椭圆"
# 添加箭头
shape4 = slide.shapes.add_shape(
MSO_SHAPE.RIGHT_ARROW,
Inches(4), Inches(3),
Inches(2), Inches(1)
)
# 常用形状类型
# MSO_SHAPE.RECTANGLE - 矩形
# MSO_SHAPE.ROUNDED_RECTANGLE - 圆角矩形
# MSO_SHAPE.OVAL - 椭圆
# MSO_SHAPE.TRIANGLE - 三角形
# MSO_SHAPE.RIGHT_ARROW - 右箭头
# MSO_SHAPE.CHEVRON - V形
# MSO_SHAPE.PENTAGON - 五边形
# MSO_SHAPE.HEXAGON - 六边形
# MSO_SHAPE.STAR_5_POINT - 五角星
# 添加线条
line_shape = slide.shapes.add_connector(
1, # 直线连接器
Inches(1), Inches(6), # 起点
Inches(5), Inches(6) # 终点
)
# 设置形状文本格式
tf = shape.text_frame
tf.paragraphs[0].alignment = PP_ALIGN.CENTER
for run in tf.paragraphs[0].runs:
run.font.color.rgb = RGBColor(255, 255, 255)
run.font.bold = True
prs.save('shapes.pptx')
6. 图片操作
from pptx import Presentation
from pptx.util import Inches
prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6])
# 添加图片
img_path = 'image.png'
left = Inches(1)
top = Inches(1)
# 方式1:自动大小
# pic = slide.shapes.add_picture(img_path, left, top)
# 方式2:指定宽度(保持比例)
pic = slide.shapes.add_picture(img_path, left, top, width=Inches(4))
# 方式3:指定宽高
# pic = slide.shapes.add_picture(img_path, left, top,
# width=Inches(4), height=Inches(3))
# 获取图片尺寸
print(f"宽度:{pic.width.inches} 英寸")
print(f"高度:{pic.height.inches} 英寸")
# 调整图片位置
pic.left = Inches(2)
pic.top = Inches(2)
# 从字节流添加图片
from io import BytesIO
# with open('image.png', 'rb') as f:
# image_stream = BytesIO(f.read())
# slide.shapes.add_picture(image_stream, Inches(1), Inches(1))
# 添加背景图片(填充整个幻灯片)
def add_background_image(slide, img_path):
"""添加背景图片"""
left = top = 0
width = slide.shapes._spTree.getparent().getparent().getparent().sldSz.attrib['cx']
height = slide.shapes._spTree.getparent().getparent().getparent().sldSz.attrib['cy']
pic = slide.shapes.add_picture(
img_path,
left, top,
int(width), int(height)
)
# 将图片移到最底层
spTree = slide.shapes._spTree
spTree.insert(2, pic._element)
prs.save('images.pptx')
7. 表格操作
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6])
# 创建表格
rows, cols = 4, 4
left = Inches(1)
top = Inches(1.5)
width = Inches(8)
height = Inches(3)
table = slide.shapes.add_table(rows, cols, left, top, width, height).table
# 设置列宽
table.columns[0].width = Inches(2)
table.columns[1].width = Inches(2)
table.columns[2].width = Inches(2)
table.columns[3].width = Inches(2)
# 填充数据
data = [
['姓名', '部门', '销量', '金额'],
['张三', '技术部', '100', '10000'],
['李四', '销售部', '150', '15000'],
['王五', '财务部', '80', '8000'],
]
for i, row_data in enumerate(data):
for j, cell_data in enumerate(row_data):
cell = table.cell(i, j)
cell.text = cell_data
# 设置单元格文本格式
paragraph = cell.text_frame.paragraphs[0]
paragraph.alignment = PP_ALIGN.CENTER
paragraph.font.size = Pt(12)
# 表头样式
if i == 0:
paragraph.font.bold = True
paragraph.font.color.rgb = RGBColor(255, 255, 255)
cell.fill.solid()
cell.fill.fore_color.rgb = RGBColor(68, 114, 196)
# 合并单元格
# table.cell(0, 0).merge(table.cell(0, 1))
# 设置边框(需要操作XML)
def set_cell_border(cell, border_color=RGBColor(0, 0, 0), border_width=Pt(1)):
"""设置单元格边框"""
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
for edge in ['a:lnL', 'a:lnR', 'a:lnT', 'a:lnB']:
ln = tcPr.find('.//' + edge.replace(':', '/'))
if ln is None:
from pptx.oxml.ns import nsmap
from lxml import etree
ln = etree.SubElement(tcPr, '{%s}%s' % (nsmap['a'], edge.split(':')[1]))
ln.set('w', str(border_width))
prs.save('tables.pptx')
8. 图表操作
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.chart.data import CategoryChartData, ChartData
from pptx.enum.chart import XL_CHART_TYPE, XL_LEGEND_POSITION
prs = Presentation()
slide = prs.slides.add_slide(prs.slide_layouts[6])
# 准备数据
chart_data = CategoryChartData()
chart_data.categories = ['1月', '2月', '3月', '4月']
chart_data.add_series('销量', (100, 150, 130, 180))
chart_data.add_series('目标', (120, 120, 150, 150))
# 添加柱状图
x, y, cx, cy = Inches(1), Inches(1.5), Inches(8), Inches(4.5)
chart = slide.shapes.add_chart(
XL_CHART_TYPE.COLUMN_CLUSTERED, # 簇状柱形图
x, y, cx, cy,
chart_data
).chart
# 设置图表标题
chart.has_title = True
chart.chart_title.text_frame.text = "月度销售数据"
# 设置图例
chart.has_legend = True
chart.legend.position = XL_LEGEND_POSITION.BOTTOM
chart.legend.include_in_layout = False
# 添加折线图
slide2 = prs.slides.add_slide(prs.slide_layouts[6])
line_chart = slide2.shapes.add_chart(
XL_CHART_TYPE.LINE,
Inches(1), Inches(1.5), Inches(8), Inches(4.5),
chart_data
).chart
line_chart.has_title = True
line_chart.chart_title.text_frame.text = "销售趋势"
# 添加饼图
slide3 = prs.slides.add_slide(prs.slide_layouts[6])
pie_data = CategoryChartData()
pie_data.categories = ['产品A', '产品B', '产品C', '产品D']
pie_data.add_series('占比', (30, 25, 20, 25))
pie_chart = slide3.shapes.add_chart(
XL_CHART_TYPE.PIE,
Inches(2), Inches(1.5), Inches(6), Inches(5),
pie_data
).chart
pie_chart.has_title = True
pie_chart.chart_title.text_frame.text = "产品占比"
# 常用图表类型
# XL_CHART_TYPE.COLUMN_CLUSTERED - 簇状柱形图
# XL_CHART_TYPE.COLUMN_STACKED - 堆积柱形图
# XL_CHART_TYPE.BAR_CLUSTERED - 簇状条形图
# XL_CHART_TYPE.LINE - 折线图
# XL_CHART_TYPE.LINE_MARKERS - 带标记的折线图
# XL_CHART_TYPE.PIE - 饼图
# XL_CHART_TYPE.DOUGHNUT - 圆环图
# XL_CHART_TYPE.AREA - 面积图
prs.save('charts.pptx')
9. 读取PPT
from pptx import Presentation
from pptx.enum.shapes import MSO_SHAPE_TYPE
prs = Presentation('presentation.pptx')
# 遍历幻灯片
for i, slide in enumerate(prs.slides):
print(f"\n=== 幻灯片 {i+1} ===")
# 遍历形状
for shape in slide.shapes:
print(f"形状类型:{shape.shape_type}")
# 文本框
if shape.has_text_frame:
for para in shape.text_frame.paragraphs:
print(f"文本:{para.text}")
# 表格
if shape.has_table:
table = shape.table
for row in table.rows:
row_text = [cell.text for cell in row.cells]
print(f"表格行:{row_text}")
# 图片
if shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
print(f"图片:{shape.name}")
# 提取所有文本
def extract_text(prs):
"""提取PPT中的所有文本"""
text_content = []
for slide in prs.slides:
slide_text = []
for shape in slide.shapes:
if shape.has_text_frame:
for para in shape.text_frame.paragraphs:
if para.text.strip():
slide_text.append(para.text)
text_content.append('\n'.join(slide_text))
return text_content
all_text = extract_text(prs)
for i, text in enumerate(all_text):
print(f"幻灯片{i+1}:\n{text}\n")
10. 实战案例
案例:自动生成数据报告PPT
"""
实战案例:自动生成数据报告PPT
"""
from pptx import Presentation
from pptx.util import Inches, Pt
from pptx.dml.color import RGBColor
from pptx.enum.text import PP_ALIGN
from pptx.chart.data import CategoryChartData
from pptx.enum.chart import XL_CHART_TYPE, XL_LEGEND_POSITION
from datetime import datetime
def create_report_ppt(data, output_file):
"""
创建数据报告PPT
Args:
data: 报告数据
output_file: 输出文件
"""
prs = Presentation()
prs.slide_width = Inches(13.333)
prs.slide_height = Inches(7.5)
# === 封面 ===
slide = prs.slides.add_slide(prs.slide_layouts[6])
# 标题
title_box = slide.shapes.add_textbox(
Inches(1), Inches(2.5), Inches(11.333), Inches(1.5)
)
tf = title_box.text_frame
p = tf.paragraphs[0]
p.text = data['title']
p.font.size = Pt(44)
p.font.bold = True
p.font.color.rgb = RGBColor(0, 51, 102)
p.alignment = PP_ALIGN.CENTER
# 副标题
subtitle_box = slide.shapes.add_textbox(
Inches(1), Inches(4.5), Inches(11.333), Inches(1)
)
tf = subtitle_box.text_frame
p = tf.paragraphs[0]
p.text = f"{data['period']} | {data['author']}"
p.font.size = Pt(24)
p.font.color.rgb = RGBColor(102, 102, 102)
p.alignment = PP_ALIGN.CENTER
# === 概述页 ===
slide2 = prs.slides.add_slide(prs.slide_layouts[6])
add_slide_title(slide2, "报告概述")
# 关键指标
metrics = data['metrics']
for i, (name, value, change) in enumerate(metrics):
x = Inches(1 + i * 3)
add_metric_card(slide2, x, Inches(2), name, value, change)
# 概述文本
summary_box = slide2.shapes.add_textbox(
Inches(1), Inches(4.5), Inches(11.333), Inches(2)
)
tf = summary_box.text_frame
tf.word_wrap = True
p = tf.paragraphs[0]
p.text = data['summary']
p.font.size = Pt(16)
# === 数据图表页 ===
slide3 = prs.slides.add_slide(prs.slide_layouts[6])
add_slide_title(slide3, "销售趋势")
# 添加图表
chart_data = CategoryChartData()
chart_data.categories = data['chart_data']['categories']
for series_name, series_data in data['chart_data']['series'].items():
chart_data.add_series(series_name, series_data)
chart = slide3.shapes.add_chart(
XL_CHART_TYPE.LINE_MARKERS,
Inches(1), Inches(1.8), Inches(11.333), Inches(5),
chart_data
).chart
chart.has_legend = True
chart.legend.position = XL_LEGEND_POSITION.BOTTOM
# === 数据表格页 ===
slide4 = prs.slides.add_slide(prs.slide_layouts[6])
add_slide_title(slide4, "详细数据")
# 添加表格
table_data = data['table_data']
rows = len(table_data)
cols = len(table_data[0])
table = slide4.shapes.add_table(
rows, cols,
Inches(1), Inches(1.8),
Inches(11.333), Inches(0.5 * rows)
).table
for i, row_data in enumerate(table_data):
for j, cell_data in enumerate(row_data):
cell = table.cell(i, j)
cell.text = str(cell_data)
p = cell.text_frame.paragraphs[0]
p.font.size = Pt(12)
p.alignment = PP_ALIGN.CENTER
if i == 0: # 表头
p.font.bold = True
p.font.color.rgb = RGBColor(255, 255, 255)
cell.fill.solid()
cell.fill.fore_color.rgb = RGBColor(68, 114, 196)
# === 总结页 ===
slide5 = prs.slides.add_slide(prs.slide_layouts[6])
add_slide_title(slide5, "总结与建议")
conclusions_box = slide5.shapes.add_textbox(
Inches(1), Inches(1.8), Inches(11.333), Inches(5)
)
tf = conclusions_box.text_frame
tf.word_wrap = True
for i, conclusion in enumerate(data['conclusions']):
if i == 0:
p = tf.paragraphs[0]
else:
p = tf.add_paragraph()
p.text = f"• {conclusion}"
p.font.size = Pt(18)
p.space_after = Pt(12)
# 保存
prs.save(output_file)
print(f"报告已生成:{output_file}")
def add_slide_title(slide, title_text):
"""添加幻灯片标题"""
title_box = slide.shapes.add_textbox(
Inches(0.5), Inches(0.3), Inches(12.333), Inches(0.8)
)
tf = title_box.text_frame
p = tf.paragraphs[0]
p.text = title_text
p.font.size = Pt(32)
p.font.bold = True
p.font.color.rgb = RGBColor(0, 51, 102)
def add_metric_card(slide, left, top, name, value, change):
"""添加指标卡片"""
# 背景框
shape = slide.shapes.add_shape(
1, # 矩形
left, top, Inches(2.5), Inches(2)
)
shape.fill.solid()
shape.fill.fore_color.rgb = RGBColor(240, 240, 240)
shape.line.fill.background()
# 指标名称
name_box = slide.shapes.add_textbox(left, top + Inches(0.2), Inches(2.5), Inches(0.5))
p = name_box.text_frame.paragraphs[0]
p.text = name
p.font.size = Pt(14)
p.font.color.rgb = RGBColor(102, 102, 102)
p.alignment = PP_ALIGN.CENTER
# 指标值
value_box = slide.shapes.add_textbox(left, top + Inches(0.7), Inches(2.5), Inches(0.8))
p = value_box.text_frame.paragraphs[0]
p.text = value
p.font.size = Pt(28)
p.font.bold = True
p.font.color.rgb = RGBColor(0, 51, 102)
p.alignment = PP_ALIGN.CENTER
# 变化率
change_box = slide.shapes.add_textbox(left, top + Inches(1.5), Inches(2.5), Inches(0.4))
p = change_box.text_frame.paragraphs[0]
p.text = change
p.font.size = Pt(12)
p.font.color.rgb = RGBColor(0, 176, 80) if '+' in change else RGBColor(255, 0, 0)
p.alignment = PP_ALIGN.CENTER
# 使用示例
if __name__ == '__main__':
report_data = {
'title': '2024年度销售报告',
'period': '2024年1-12月',
'author': '销售部',
'summary': '本年度销售业绩整体表现良好,总销售额达到1.2亿元,同比增长15%。'
'其中Q4表现最为突出,贡献了全年35%的销售额。',
'metrics': [
('总销售额', '1.2亿', '+15%'),
('订单数', '12,580', '+8%'),
('客户数', '3,256', '+12%'),
('客单价', '9,538', '+6%'),
],
'chart_data': {
'categories': ['1月', '2月', '3月', '4月', '5月', '6月',
'7月', '8月', '9月', '10月', '11月', '12月'],
'series': {
'2024年': [800, 850, 920, 880, 950, 1000, 1050, 1100, 1150, 1200, 1300, 1400],
'2023年': [700, 720, 780, 800, 850, 880, 900, 950, 980, 1000, 1050, 1100],
}
},
'table_data': [
['产品', 'Q1', 'Q2', 'Q3', 'Q4', '合计'],
['产品A', '2000', '2500', '2800', '3200', '10500'],
['产品B', '1500', '1800', '2000', '2500', '7800'],
['产品C', '1000', '1200', '1500', '1800', '5500'],
],
'conclusions': [
'销售额同比增长15%,超额完成年度目标',
'产品A仍是主力产品,贡献45%的销售额',
'Q4销售旺季表现突出,建议加大备货',
'新客户增长12%,客户维护工作成效显著',
'建议2025年重点拓展产品C的市场份额',
]
}
create_report_ppt(report_data, '销售报告.pptx')
11. 总结
🔑 核心要点
| 知识点 | 要点 |
|---|---|
| 创建PPT | Presentation(), add_slide() |
| 文本 | add_textbox(), text_frame, add_paragraph() |
| 形状 | add_shape(), 填充、边框设置 |
| 图片 | add_picture(), 指定位置和大小 |
| 表格 | add_table(), 单元格操作 |
| 图表 | add_chart(), CategoryChartData |
✅ 学习检查清单
- 能创建PPT并添加幻灯片
- 能添加和格式化文本
- 能添加形状和图片
- 能创建表格
- 能添加图表
📖 下一步学习
掌握了PPT操作后,让我们学习邮件自动化:
常见问题 FAQ
💬 python-pptx能保留原PPT的动画效果吗?
不能。python-pptx不支持动画、过渡效果和视频嵌入。如果需要保留这些,只修改文本和数据内容,不要重新创建幻灯片。
💬 怎么用现有模板生成PPT?
用Presentation("template.pptx")加载模板,然后在模板基础上添加或修改幻灯片。模板中的母版和布局会被保留。
� 系列导航
- 上一篇:17 - Python操作Word
- 当前:18 - Python操作PPT
- 下一篇:19 - Python邮件自动化