书名:Python办公效率手册
ISBN:978-7-115-57006-7
本书由人民邮电出版社发行数字版。版权所有,侵权必究。
您购买的人民邮电出版社电子书仅供您个人使用,未经授权,不得以任何方式复制和传播本书内容。
我们愿意相信读者具有这样的良知和觉悟,与我们共同保护知识产权。
如果购买者有侵权行为,我们可能对该用户实施包括但不限于关闭该帐号等维权措施,并可能追究法律责任。
著 麦 叔
责任编辑 赵 轩
人民邮电出版社出版发行 北京市丰台区成寿寺路11号
邮编 100164 电子邮件 315@ptpress.com.cn
网址 http://www.ptpress.com.cn
读者服务热线:(010)81055410
反盗版热线:(010)81055315
本书从日常办公场景和职场人的实际工作需求出发,以实战案例为主线,分解一个个任务,用轻松的方式讲解使用Python编程语言解决办公难题、提升工作效率的知识与方法,内容涵盖:使用Python处理大量重复性的Word文档、Excel表格工作,以此大大提升工作效率;巧用Python处理PDF文档、PPT演示、电子邮件、图形图像,实现专业的内容输出;编写Python爬虫程序,抓取网络数据信息。这些知识是大部分人学习Python的目的所在,对职场办公人士、科研人员和大学生都有很大的帮助。
不知道大家有没有感觉到,“Python”这个单词在你的办公室里越来越频繁地出现。Python本身是一门编程语言,原本只有程序员才会关心,现在可好,公司里的很多人都在用它,尤其是那些擅长使用软件工具的“精英”。以往需要用到复杂Excel技巧的工作,他们只需要敲几行代码,就能瞬间完成,很让人羡慕。
不仅如此,还有很多让人头大的任务,如果用常规方法去处理,既费时又费力,关键还不一定能搞定。此时如果用Python来处理,则轻松到令人难以置信,工作效率倍增。
作为一门“万能语言”,Python受欢迎的程度可想而知,最可贵的是,Python的学习门槛很低,很多小学生都能在课本的帮助下学会简单的Python编程方法。对于完全没有接触过Python的人,麦叔也准备了一份Python入门教程—《麦叔带你学Python》,帮助你建立起对Python的基本认识。
而在你手中的这本书里,麦叔侧重于把自己多年来用得很顺手的Python办公方法和技巧分享给大家。
你可能是一名刚刚工作不久的办公室职员,每天都要重复性整理大量的Word/Excel文档;你也可能是一名需要对部门业绩负责的管理者,总需要从不同的维度分析手头的经营数据,这本书能够帮助你从以往的工作方法中找到一条新路,虽然会让你花上一些学习成本,但当你真正掌握了Python的精髓之后,以往很多恼人的任务,完全可以通过编程实现自动化处理。这不仅大大提升了你的工作效率,更能让你的思维水平提升一个层次。
麦叔曾是一名程序员,不光热爱编程工作,甚至沉迷于对源码的解析。多年以后,我成为了一名技术管理者,渐渐地,我看待问题的角度也发生了微妙的变化,享受于利用精心编写的代码瞬间解决业务难题的美妙瞬间。
后来我发现,将专业Python编程的思路、方法和技巧,应用于日常办公,也能产生事半功倍的奇效,因此我将这些适用性特别强的方法分享给我的同事们和公众号的读者,没想到引起了共鸣,大家纷纷将自己的知识分享出来。这就是本书的由来。
学习Python不仅可以让你的工作变得更加有趣和高效,还可以让你个人变得更有价值。麦叔的朋友—韩梅梅—可以证明这一点。
当初为了进一个更有名气的工科大学,高考分数不太高的韩梅梅只能退而求其次选择了这所工科大学的英语专业。虽然她的专业八级的成绩不错,但做不了高水平的同声传译工作,因此走不了“英语专业路线”;另外,英语专业学生由于偏向文科,又很难胜任技术型岗位……好在韩梅梅是一个非常积极上进的人,她相信只要勤奋和善于思考,就一定能有好的发展。于是她开始努力地投简历、应聘、面试,最后进入了一家文化公司做文秘工作。
在韩梅梅入职后的第二个月,她就遇到了第一个难题。周四下午6点35分,韩梅梅和几个同事刚要下班离开办公室,领导就叫住了她们。任务的逻辑本身并不复杂,但由于种种原因而变得很紧急:公司今年要操办某大牌乐队的线上演唱会,一共卖出了10万张票,这意味着公司要为10万名观众制作电子邀请函(演唱会的电子门票),并且要通过电子邮件将邀请函发送给每一位观众。
邀请函已经由设计师设计好,并且通过公司审核定稿。
同时,老板给韩梅梅发过来一份Excel文档,里面是10万名观众的信息。
领导的要求也很简单:“东西我全都准备好了啊,这个周末要把邀请函都发出去,靠你们啦,大伙儿辛苦一下。”
公司文秘组的王姐是主管,来公司5年了,有丰富的业务经验,十分可靠,也懂得照顾新人;张姐来这个公司快两年了,之前还在其他公司做过文案工作;韩梅梅是最年轻的新员工,刚好补上去年年底离职小妹的空缺。她们三人此时面面相觑,因为与以往承接的各种小型演出和大型现场演唱会不同,这次的演唱会不仅规模大,而且涉及很多线上组织工作,大家心里都没有底。
要想把这10万份邀请函通过电子邮件发给观众们,如果手工处理,步骤大概是这样的。
① 复制Word模板(大约1秒)。
② 从Excel表格中复制一名观众的信息,替换Word模板里的内容(大约12秒)。
③ 修改word文档名(大约2秒)。
④ 发送电子邮件(大约15秒)。
就算按上述步骤进行,每份邀请函的制作与发送工作只需要30秒,处理10万份也需要50000分钟,也就是需要833小时,仅靠她们三人断然不可能在下周一前搞定。
王姐是一个干练的人,她快速做出部署。
韩梅梅犹豫了一下,但还是鼓起勇气说:“王姐,我学过Python,要不我来试试写程序?如果能写好,说不定我们周五还能按时下班。”
王姐看了一眼韩梅梅:“你能行吗?”
韩梅梅虽然心里没底,但是她文静的外表下其实有一颗“舍我其谁”的心,她使劲点了点头。
王姐在微信朋友圈里经常会刷到Python培训广告,想去学一学,但一直很忙,没有时间。所以她在稍加考虑后,决定让韩梅梅试一试,并改变了部署。
为了顺畅高效地学习本书的知识,和韩梅梅一起用Python开启高效办公之旅,读者最好预先掌握基本的Python知识。为此,麦叔精心编写了本书的免费配套资料《麦叔带你学Python》,以此种形式帮助读者快速掌握基本功。
此外,本书还需要读者做好一些简单的准备工作。
如果你还没有实现上面这些,《麦叔带你学Python》可以帮你解决所有的问题,你可以现在就去学习这本免费的电子书,也可以继续阅读本书,遇到了问题再去翻阅。
免费电子书获取方法:关注公众号麦叔编程,回复book1。
获取本章代码和相关资料:关注公众号麦叔编程,回复book2。由于本书前4章相互关联,因此各章的资料是放在一起的。
本书后面提到“相关资料”时就是指公众号上提供的资料。
为了完成这项又急又重的任务,韩梅梅计划把它拆解成4个小任务,也就是4个程序。
程序1:给指定的人(比如张三)自动生成Word邀请函。
程序2:从Excel表格中读取名单,调用程序1为每个人生成邀请函,并保存到文件夹中。
程序3:使用电子邮件给指定的人(如李四)发送邀请函。
程序4:从Excel表格中读取每个人的电子邮件地址,调用程序3发送邀请函。
思考一下:生成每一份邀请函后马上发电子邮件,与先批量生成邀请函再依次发送,两种方法的优势和劣势各是什么?
把一个大任务拆解为若干小任务,然后各个击破,是韩梅梅上学的时候就养成的好习惯,同样可以应用在编程上。
把一个大程序分解成几个小程序,这些小程序可能是函数,也可能是模块。小程序写完了,大程序也就搞定了。
当然,这是一个综合程序,在执行过程中可能会碰到意料之外的问题,比如在一个文件夹中放10万个文档可能会让文件夹根本无法打开。但一开始不用太担心这些问题,理清大的思路,一步步走下去,碰到问题再解决就是了。
韩梅梅虽然掌握了一些Python编程基础知识与方法,但是如何用Python自动生成Word文档她并不了解。但是她知道Python之所以强大,是因为Python拥有极为丰富的模块,几乎可以应对所有的日常任务。所以,只要找到合适的模块,她就应该能解决眼下的难题。
对,就这么干!要解决一个问题,首先应看看是否已经有人写好了相关的模块。
韩梅梅根据自己的任务特点,在网上搜索到了很多与Word相关的模块,最后决定使用python-docx模块。
要使用python-docx模块,需要先把它安装到自己的计算机上,命令如下:
python -m pip install python-docx
韩梅梅打开代码编辑器,新建了一个名为hello.py的文件(Python代码),并在文件中写入如下代码:
import docx
# 使用docx模块的Document类创建新文档,并赋值给变量doc
doc=docx.Document()
# 在文档doc中添加一行标题样式的文字
doc.add_heading('我的第一个自动Word文档', 0)
# 把doc保存到硬盘,取名为hello.docx
doc.save('hello.docx')
参考源码:hello.py(可以在参考资源中找到)
在命令行窗口下运行代码,韩梅梅看到在同目录下出现了名为hello.docx的文档,这就说明文档创建成功。
运行代码的步骤是,打开命令行,并切换到代码所在的目录,然后执行:
python hello.py
值得注意的是,这里安装的模块是python-docx,但使用import命令引入的时候使用的是docx。
TIPS
代码中#号后面的内容,为麦叔对代码的解释说明,它们不会对代码产生任何效果。
这时基本工作做好了,但是关键问题来了,如何用python-docx生成邀请函呢?
韩梅梅打开邀请函模板,仔细观察了一下(图1.1)。
图1.1
模板中所有标识<name>的地方,都要用Excel表格中观众的真实名字来替换。因为已经确定了模板,所以韩梅梅并不需要从零开始用代码生成邀请函文档,只需在模板上替换名字就可以了。假设要为名为“张三”的观众生成邀请函,那么只需要3步。
① 打开邀请函模板。
② 把模板中的所有<name>替换成“张三”。
③ 保存文档,并把新文档命名为“张三.docx”。
不管是手工操作,还是用程序自动实现,过程都是一样的。
接下来,韩梅梅新建了一个名为invite.py的文档,然后写入如下代码:
import docx
name = '张三' # 观众的名字
template = 'template.docx' # 模板的文档名
name_placeholder = "<name>" # 要被替换的字符,也被称为占位符
doc = docx.Document(template)
# 循环遍历每个段落
for para in doc.paragraphs:
if name_placeholder in para.text:
# 循环遍历段落中的每一组文字
for run in para.runs:
if name_placeholder in run.text:
# 用具体名字替换占位符
run.text = run.text.replace(name_placeholder, name)
doc.save(f'{name}.docx')
参考源码:invite1.py
在理解代码之前,需要理解Word文档的结构。假设Word文档的名字为doc,某个段落名为para。
一个文档中有多个段落,用doc.paragraphs获取;段落中的文字用para.text获取。
一个段落中可能会有多种不同样式的文本,比如“麦叔是一个程序员”这句话包含了3种不同的样式。其中,“麦叔”为粗体,“是一个”三个字为正常字体,“程序员”三个字为斜体。这些不同的样式被称为run。一个段落包含多个run,用para.runs获取。一个run中的具体文本用run.text获取。
了解了这些内容,现在再来看代码就容易懂了。
首先定义3个变量,分别为观众的名字、模板文档的名字,以及要被替换的字符串。这些变量在后面会被反复使用。
然后使用docx.Document(template)加载模板文档。当Document没有参数的时候就创建新文档,有参数的时候就加载参数指定的文档。这里通过template变量指定了模板文档的名字为template.docx。模板文档被赋值给变量doc。
再循环遍历doc中的每个段落,其中doc.paragraphs是文档中所有的段落。
第10行判断当前段落中的文字para.text是否包含要被替换的字符name_placeholder,如果包含则处理该段落。
接着循环处理段落中的每个run,判断run.text中是否包含name_placeholder:如果包含,则使用run.text.replace()函数把name_placeholder替换为name,也就是张三。把替换后的文字赋值给run.text,这样就改变了这段文本的内容。
下载template.docx并保存到代码的同一个目录下,然后运行程序,就会生成“张三.docx”。打开检查一下,里面的占位符都被替换成了“张三”(图1.2)。
图1.2
你可能会想,是否可以直接替换para.text,这样就不用去循环处理run了。
这是一个很好的想法,但行不通。因为直接去替换para.text会导致样式丢失,不信你就试一试。
为了方便以后反复使用,韩梅梅把上面的代码放到了一个函数中,把要被替换的名字用参数传递进去:
import docx
def invite(name):
template = 'template.docx' # 模板的文档名
name_placeholder = "<name>" # 要被替换的字符,也被称为占位符
doc = docx.Document(template)
# 循环遍历每个段落
for para in doc.paragraphs:
if name_placeholder in para.text:
# 循环遍历段落中的每一组文字
for run in para.runs:
if name_placeholder in run.text:
# 用具体名字替换占位符
run.text = run.text.replace(name_placeholder, name)
doc.save(f'{name}.docx')
invite('张三')
invite('李四')
参考源码:invite2.py
这段代码创建了一个名为invite的函数,它只有一个参数name,表示观众的名字。然后调用两次这个函数,为张三和李四创建邀请函。
运行上面的代码,应该会生成“张三.docx”和“李四.docx”。检查里面的内容,确保名字都被正确替换。
到这里,韩梅梅顺利地完成了第一个小任务,也就是给指定的人自动生成Word邀请函。
接下来,只要能从Excel表格中读取所有人的信息,就可以为每个人生成一份邀请函。
在继续执行下一个任务之前,我们来系统梳理一下自动处理word文档的关键知识。
看完了韩梅梅的案例,让我们回过头来系统回顾一下Word自动化技术,加强你对相关知识的理解。
Word文档不同于普通的记事本文档,它包含了字体、大小、颜色和其他样式信息。Word文档结构如下(图1.3)。
图1.3
一个文档中可能包含多个段落(paragraph),一个段落可能由多种不同字体样式的部分组成。这些不同的字体样式被称为run。
在示例文档中共有6个段落,其中的标题也算是一个段落。如果文档的下面有空行,也会被识别为段落。
倒数第二段包含了粗体、斜体、黄色背景以及红色文字样式。每当有字体或者样式的变化,都会产生一个新的run。
下面我们来读取文档并验证里面的内容:
import docx
doc=docx.Document('Word文档示例.docx')
# 使用len()函数获取段落数
pnums=len(doc.paragraphs)
print(f'本文档共有{pnums}个段落')
for index, p in enumerate(doc.paragraphs):
# 打印每个段落中run的个数
print(f'第{index+1}段有{len(p.runs)}个run')
参考源码:read_doc.py
要读取文档的文本内容,并没有类似doc.text这样的方法,但我们可以读取paragraph和run中的文本:paragraph.text和run.text。
让我们继续完善上面的程序,读取各段落中的内容:
print('============我们通过p.text读取段落中的文本')
for p in doc.paragraphs:
print(p.text)
也可以分别读取每个run中的文本:
print('============我们通过r.text读取run中的文本')
for index, p in enumerate(doc.paragraphs):
print(f'第{index+1}段有{len(p.runs)}个run:')
for r in p.runs:
print(r.text)
总结一下,读取文档中的文本的方法如下。
我们可以通过下面的代码来验证它们分别是什么类型的数据:
print('============查看各种对象的类型')
print(f'doc是:{type(doc)} 类型')
print(f'doc.paragraphs是:{type(doc.paragraphs)} 类型')
print(f'paragraph是:{doc.paragraphs[0]} 类型')
print(f'paragraph.runs是:{type(doc.paragraphs[0].runs)} 类型')
print(f'run是:{type(doc.paragraphs[0].runs[0])} 类型')
前面我们说过,Python-docx模块中并没有可以读取整个文档中所有文本的方法,但我们可以自己动手实现一个:
import docx
def read_doc(filename):
"""
给定docx文档的名字,返回文档的所有文本内容,不同段落用\n隔开
"""
doc = docx.Document(filename)
texts = []
for p in doc.paragraphs:
texts.append(p.text)
return '\n'.join(texts)
full_text = read_doc('Word文档示例.docx')
print(full_text)
参考源码:read_doc2.py
接着,我们尝试做一些改进。
比如,要在每个段落中间再加一个空行,只需在join前增加两个\n即可:
'\n\n'.join(texts)
要在每个段落的开头都加上两个空格,只需要在调用append()函数的时候多传入两个空格:
texts.append(' ' + p.text)
另外,如果我们写错了文档的名字,程序就会报错,但是这些错误只有程序员才能看懂。为此,我们可以进一步完善代码,让它能够给出更清晰的提示:
import docx
def read_doc(filename):
"""
给定docx文档的名字,返回文档的所有文本内容,不同段落用\n隔开
"""
try:
doc = docx.Document(filename)
except:
return f'读取文档出错,可能是文档名不对:{filename}'
texts = []
for p in doc.paragraphs:
texts.append(p.text)
return '\n'.join(texts)
full_text = read_doc('Word文档示例1.docx')
print(full_text)
最开始我们就尝试了创建一份全新的文档,将内容写入文档。我们可以先看一下docx的Document对象提供了哪些方法:
import docx
import pprint
doc=docx.Document()
print('doc包含如下方法:')
pprint.pprint(dir(doc))
在这些方法中,以双下划线“__”或者单下划线开头的都是私有的方法,外人是不应该使用的,麦叔也不推荐你使用。另外,我们看到有好几个以add开头的方法,这些就是往里面添加内容的方法啦:
add_paragraph
add_run
add_title
addpagebreak
下面的代码使用了这些方法:
import docx
import pprint
doc = docx.Document()
print('doc包含如下方法:')
pprint.pprint(dir(doc))
doc.add_paragraph('这是第一段!')
p2 = doc.add_paragraph('这是第二段!')
p2.add_run('网址是:qingke.me')
doc.add_page_break()
doc.add_paragraph('这是第四段')
doc.save('newdoc.docx')
参考源码:create_doc.py
答案源码:answer.py
练习的相关答案,可以在本章资料中获得。
韩梅梅只是在邀请函中替换了模板中的人名,要想增强这个程序,除了替换名字,也要替换电话号码和座位号。
这时候的模板也有所变化,里面出现了PHONE和SEAT两个额外的占位符用来表示电话和座位号。这两个占位符没有使用尖括号,但这不要紧,只要替换的时候不加尖括号就可以了(图1.4)。
图1.4
请使用template2.docx作为模板:
from docx import Document
NAME = '<name>'
PHONE = 'PHONE'
SEAT = 'SEAT'
def invite(name, phone, seat):
doc = Document('template2.docx')
for p in doc.paragraphs:
for r in p.runs:
if NAME in r.text:
r.text = r.text.replace(NAME, name)
if PHONE in r.text:
r.text = r.text.replace(PHONE, phone)
if SEAT in r.text:
r.text = r.text.replace(SEAT, seat)
doc.save(f'{name}-{phone}.docx')
invite('张三', '18812345678', 'D3B20')
参考源码:invite3.py
这段代码首先定义了3个占位符,然后给invite()函数添加了phone和seat两个参数表示手机和座位号(原本有name参数),并用这3个参数分别替换NAME、PHONE和SEAT 3个占位符,最后给文档名字也加了电话号码。
本章虽然不能涵盖Word自动化的所有方面,但重点介绍了Python办公自动化的核心概念和思路,并通过一个日常工作中经常会遇到的案例,介绍了使用Python办公自动化处理Word文档的方法。
自动生成邀请函的程序很简单:打开模板,替换内容,保存文档。这一系列操作同样可以应用在自动生成合同、自动生成门票等需要大量重复制作Word文档的场景。