2023年11月26日发(作者:)
Python⾃动化之操作PPT--更新模板数据,减少重复操作
使⽤Python操作PPTX之保留原PPT模板只更改数据
Python⾃动化之操作PPT
⽇常⼯作中会遇见很多重复性的操作,利⽤Python可以让我们从繁忙的⼯作中解脱出来。本次要分析的就是运⽤Python操作PPT以实现⾃
动化⽣产PPT⽂件。
需求分析
⼯作中⼀同事需要结合Excel数据来制作PPT报告,以便甲⽅更好的看到商品部分指标的变化趋势。⽬前同事已经做好了⼀个模板⽂件,需
要完成将它运⽤到其他数据上。
PPT样式如下:
问题分析以及思路分享
原需求是想运⽤Python来⽣成PPT⽂件,于是需要了解到Python操作PPT的库,根据这个库来⽣成想要的PPT⽂件。
第⼀次尝试
由于第⼀次接触到Python操作PPT,在⽹上得知,Python操作PPT的库为python-pptx。于是安装python-pptx.
pip install python-pptx
安装完之后就可以对pptx进⾏操作了。
由于第⼀次使⽤有些操作不是很熟,阅读了⽹上的⼀些案例,结合 便开始⼀顿操作了。
可当正要操作是便发现,⽹上的⼤多数教程都是如何创建⼀页简单的PPT,讲到了Presentation,占位符等对象,可如上图所⽰,我操作的
是⽣成⼀个图表,还有⼀个表格,当PPT播放时,折线图还有⼀个动态的过程。于是我陷⼊了沉思,这个轮⼦我可造不了,对于python-
pptx我还不是很了解,这可不能快速的完成⾃动化的任务。
第⼆次尝试
虽然我不能创建PPT,但是⽬前已经有⼀个做好的模板PPT,借助于前段时间做过的⽣成报告证书的经历,报告证书是其中⼤多数数据不变,
变化商品名称和⽇期然后输出pdf⽂件,在模板⽂件中运⽤占位符就可以解决。于是顺着这个思路,我能否通过读取PPT模板,修改其中的
部分数据,⽽不改变结构,那么问题也就解决了。
于是运⽤python-pptx读取pptx⽂件,获取该对象,对该对象进⾏操作。
此时不得不打开官⽅⽂档了解其属性⽅法,⼀遍对其更好的操作。
慢,这样⼀来不⼜是进⼊了造轮⼦的阶段吗,我并不需要对pptx库进⾏全⾯的了解,核⼼是对数据进⾏替换。于是我只需要知道原PPT中⼀
个数据对应的属性⽅法是什么就可以了(有点像爬⾍),通过值找到对应的标签。下⾯正式开始。
读取pptx⽂件,读取⼀些基本知道该对象的属性⽅法
from pptx import Presentation
prs = Presentation("")
slides = prs.slides
number_pages = len(slides)
page = slides[0]
print(dir(page.shapes))
有上⾯输出可以得到 每个PPT页⾯的对象都为⼀个slider,每页中出现的内容都在中。
可以发现有如下属性:
‘adjustments’, ‘auto_shape_type’, ‘click_action’, ‘element’, ‘fill’, ‘get_or_add_ln’, ‘’,
has_chart
‘’, ‘has_text_frame’, ‘height’, ‘is_placeholder’, ‘left’, ‘line’, ‘ln’, ‘name’, ‘part’,
has_table
‘placeholder_format’, ‘rotation’, ‘shadow’, ‘shape_id’, ‘shape_type’, ‘text’, ‘text_frame’, ‘top’,
‘width’。
结合对pptx的初步了解,
text是和⽂字相关的,table是和表格相关的,chart是和图表相关的,其他的有⼀些边框⼤⼩,填充字体等属性。于是接着尝试
for shape in page.shapes:
# print(dir(shape))
if shape.has_chart:
print("ok")
if shape.has_tacle:
print("ok")
果然,返回的结果都是ok,也就是刚好和原来PPT中的折线图以及表格相对应。(感觉发现了新世纪的⼤门)
接着就是分别对chart和table进⾏操作了。(由于⾛了很多坑这⾥的顺序和实际完成的顺序不太⼀样)
对table进⾏操作
table做为⼀个表格对象,从原图就可以看出,table有如下⼏种属性:变宽间距,字体颜⾊,字体形式,字体⼤⼩,对齐⽅式。刚好这⾥在
table对象都有了很好的体现。⽽我要做的就是如何修改这些达到要求。这其中对于字体颜⾊,有些原pptx的颜⾊在python-pptx中并读不
出来,这⾥的⼩技巧就是通过取⾊器获取原ppt⽂件中字体的RGB颜⾊,然后⽤python创建这样的⼀个颜⾊对象,来填充之前的属性。
for shape in page.shapes:
if shape.has_table:
table = shape.table
# tableopenpyxl
获取的⼀个格,类似
ii = 2
j = 1
cell = table.cell(ii, j + 1)
#
填充的数据
da = get_da(ci, j + 1)
pr = cell.text_frame.paragraphs[0].runs[0]
pr.text = da
#
字体⼤⼩
pr.font.size = Pt(11)
if da == "-" or da == "0%":
#
颜⾊
pr.font.color.rgb = RGBColor(0, 0, 0)
elif "-" in da:
pr.font.color.rgb = RGBColor(156, 0, 6)
else:
pr.font.color.rgb = RGBColor(84, 130, 53)
#
字体
pr.font.name = "Arial"
⼤功告成,table的给中属性和实际使⽤吻合很⾼。
对chart进⾏操作
在对chart进⾏操作时,可以得到chart本⾝的属性。于是直接查看chart的属性和⽅法:
for shape in page.shapes:
if shape.has_chart:
chart = shape.chart
print(dir(chart))
chart_data = ChartData(chart)
cart = chart_data.categories
for s in cart:
print(s)
print(s.label)
for s in chart.series:
print(s.data_labels.show_value)
print(s.name)
可以找到chart有如下属性:
‘category_axis’, ‘chart_style’, ‘chart_title’, ‘chart_type’, ‘element’, ‘font’, ‘has_legend’, ‘has_title’,
‘legend’, ‘part’, ‘plots’, ‘replace_data’, ‘series’, ‘value_axis’
这些和Python中的图都很相似,于是我尝试获取到了图表中的值也惊奇的发现,视乎离成功更近⼀步了。下⼀步就是想如何改变这些值成
新的值了。于是我发现了replace_data⽅法,是否运⽤replace⽅法就可以完成操作了,于是我查找了相关replace的使⽤⽅式,通过不断
努⼒发现数据可以该但是并不是我想要的样⼦。没有了之前的动态显⽰过程,操作过程也⽐较复杂,当我在ppt编辑数据时,原数据居然没
有变化,我深知这事还没有结束。于是我去查找API发现其中这样⼀个描述
class ries
A data point series belonging to an area plot.
...
values
Read-only. A sequence containing the float values for this series, in the order they appear on the chart.
也就是说我获取到的图表区,部分参数是只读的,仔细⼀想图表是原数据的⼀种可视化表现,这⾥的chart对象只是图表的展⽰对象去,其
数据也相当于⼀个备份,改变chart属性时并没有实际改变源数据,所以只会在图形上⼀时的显⽰更改后的效果,不说这个过程有多复杂,
最终也不能实际完成⼯作。
于是我在这⾥卡住了。
最终的解决
由于上述问题⼀时卡住了我,我就先去忙其他的活了,可这终究是⼀到坎,我想着越过它。于是顺着上⾯的思路,加上实际的操作,每次⼈
⼯操作都是点击编辑数据之后,复制粘贴来完成。这样⼀想,python读了了ppt⽂件,将其转换为⼀个对象,表格,可以看得见的图标,都
可以在这个对象中找到,那编辑数据处的原数据应该也在原始的shape对象中。我得找到它。
我查看了chart_part属性,这让我眼前⼀亮[‘before_marshal’, ‘’, ‘’, ‘’, ‘content_type’,
blobchartchart_workbook
‘drop_rel’, ‘load’, ‘load_rel’, ‘new’, ‘package’, ‘part’, ‘part_related_by’, ‘partname’,
‘partname_template’, ‘relate_to’, ‘related_parts’, ‘rels’, ‘target_ref’]
这其中就有chart,我欣喜的是发现了***chart_workbook***,这让我想起了Excel,python中操作Excel的openpyxl中就有workbook。于
是我得好好的找找如何修改这个Excel⽂件的⽅法。
初步我发现了chart_workbook有如下属性和⽅法
class ChartWorkbook(builtins.object)
| ChartWorkbook(chartSpace, chart_part)
|
| Provides access to the external chart data in a linked or embedded Excel
| workbook.
|
| Methods defined here:
|
| __init__(self, chartSpace, chart_part)
| Initialize self. See help(type(self)) for accurate signature.
| # xlsxblobworkbook
使⽤⽂件的格式数据更新这个
| update_from_xlsx_blob(self, xlsx_blob)
| Replace the Excel spreadsheet in the related |EmbeddedXlsxPart| with
| the Excel binary in *xlsx_blob*, adding a new |EmbeddedXlsxPart| if
| there isn't one.
|
| ----------------------------------------------------------------------
| Data descriptors defined here:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
|
| xlsx_part
| Return the related |EmbeddedXlsxPart| object having its rId at
| `c:chartSpace/c:externalData/@rId` or |None| if there is no
| `<c:externalData>` element.
发现chart_workbook中有⼀个blob⼆进制⽂件,这⾥经过不断尝试确定excel的内容就是以⼆进制存在blob中,如此凭着试⼀试的⼼态,
我以⼆进制形式读了⼀个xlsx⽂件,然后结合update_from_xlsx_blob⽅法,想着能不能更新数据。
wbda = open("","rb").read()
#
遍历每⼀个幻灯⽚的形状
for shape in pager.shapes:
# print(_chart)
if shape.has_chart:
# print(help(shape))
chart_part = shape.chart_part
chart_workbook = chart_part.chart_workbook
chart_workbook.update_from_xlsx_blob(wbda)
chart = shape.chart
#
是否能直接更新表格不需要⼈⼯处理,实际并不能
# chart.__init__(chartSpace=chart._chartSpace,chart_part=chart_part)
运⾏完成,打开新⽣产的⽂件,第⼀眼发现折线图并没有改变,觉得⾃⼰⼜失败了,可当我点击编辑数据后,折线图⽴刻发⽣了变化,播放
PPT原来的折线图的动态过程还在。总算是⼤功告成了,唯⼀美中不⾜的就是最后还需要⼿动点⼀下编辑数据。当然这个可以交个Python
去做,暂时想到的就是Python模拟⼈去点击,相关的知识下次再分享了。
⼩结
本次使⽤Python借助PPT模板⾃动⽣成同样样式的PPT。这其中⾛了很多弯路,让我学会了很多东西,强化了对⼀些知识的认识。
1:解决问题时要有不同的思路,⽬的是⽣成同样样式的PPT,那么可以尝试⾃⼰直接⽤Python⽣成,也可以直接对已经完成的模板进⾏修
改。亦或者是不直接操作使⽤python-pptx库,使⽤⾃动化控制软件去模拟⼈的操作⾏为,等等,只要最终问题得到了解决那就已经是⼀种
进步
2:⼀切皆对象,对象就有属性和⽅法,通过阅读API⽂档并结合实际操作可以快速的了解⼀个库。⽽实际对象转换时,⾁眼看的见的数据
或者图形都有可能转换成python中的对象,那么实际ppt所包含的字体,颜⾊,变宽,⼤⼩,图形,表格等都会在python转换的对象中存
在,结合实际问题,就可以合理运⽤属性和⽅法来快速掌握⼀个库的使⽤。完成任务。


发布评论