欢迎光临
我们一直在努力

《超简单:用 Python 让 Excel 飞起来》读书笔记:第4章 案例06 批量打印工作簿

avatar

🔥
个人主页:
杨利杰YJlio

❄️
个人专栏:
《Sysinternals实战教程》
《Windows PowerShell 实战》
《WINDOWS教程》
《IOS教程》

《微信助手》
《锤子助手》
《Python》
《Kali Linux》

《那些年未解决的Windows疑难杂症》
🌟
让复杂的事情更简单,让重复的工作自动化

请添加图片描述

在这里插入图片描述


《超简单:用 Python 让 Excel 飞起来》读书笔记:第4章 案例06 批量打印工作簿

  • 1. 第4章 案例06:批量打印工作簿
  • 2. 应用场景:哪些情况适合批量打印
  • 3. 核心原理:xlwings 的 api 与 PrintOut
  • 4. 基础代码:批量打印文件夹下所有工作簿
  • 5. PrintOut 常用参数:不要只会默认打印
  • 6. 进阶场景:只批量打印指定工作表
  • 7. 打印前检查:批量打印最怕“错得很快”
  • 8. 更稳的版本:加入日志与异常处理
  • 9. 效果验证:脚本跑完后应该看什么
  • 10. 总结提升:批量打印不是炫技,是流程标准化

1号标题图

1. 第4章 案例06:批量打印工作簿

V4修正版进度标记:本篇为 06月20日 第2篇,继续整理《超简单:用 Python 让 Excel 飞起来》第4章办公自动化案例。

  这一篇整理的是 第4章 案例06:批量打印工作簿。前面几节更多是在做“批量新建、批量打开、批量修改、批量保存”这些文件处理动作,而这一节开始进入更典型的办公室场景:一个文件夹里有很多 Excel 工作簿,需要统一打印出来。

  这类需求在实际办公中很常见。比如月度报表要打印留档,分部报表要统一提交,会议材料要提前装订,财务、行政、项目管理岗位都可能遇到类似场景。手工做法通常是:打开一个文件,按 Ctrl + P,选择打印机,点击打印,关闭文件,然后再打开下一个文件。

  如果只有两三个文件,手工打印没问题;但如果是几十个甚至上百个工作簿,继续手动点击就是低价值重复劳动。

  这张图展示的是本文的核心主题:通过 Python 调用 Excel 自动化能力,把多个工作簿批量发送到打印机。

请添加图片描述

  从图中可以看出,批量打印不是简单地“让打印机出纸”,而是把文件夹遍历、工作簿打开、打印命令调用、资源释放这几步串成一个稳定流程。这个案例的关键点在于 workbook.api.PrintOut(),它不是普通的 Excel 文件读写,而是通过 xlwings 的 .api 调用 Excel 底层对象模型能力。

  简单理解:xlwings 负责连接 Python 和 Excel,PrintOut 负责调用 Excel 自身的打印能力。这也是这一节和前面“读写单元格”类案例最大的区别。

2号标题图

2. 应用场景:哪些情况适合批量打印

  批量打印脚本适合规则明确、文件数量较多、打印要求相对一致的场景。比如一个目录下全是待打印报表,每个工作簿都已经设置好页面布局、打印区域、纸张方向和页边距,这种情况下用 Python 批量触发打印,会比手工操作稳定得多。

  这张图展示的是批量打印的典型应用场景,包括月度报表、分部汇总和会议资料。

请添加图片描述

  从图中可以看出,批量打印并不是一个“孤立技术点”,它对应的是非常现实的办公流程。月度报表强调的是周期性,分部汇总强调的是多文件统一处理,会议资料强调的是集中输出和装订。它们共同的特点是:文件多、规则固定、人工重复操作没有技术含量。

  推荐使用批量打印脚本的前提是:打印范围已经在 Excel 文件里设置清楚,文件命名和目录结构也比较稳定。如果文件本身排版混乱、打印区域没设好、工作表数量不一致,那么脚本只会把混乱放大。

  我自己的判断是:批量打印脚本不是第一步,而是最后一步。前面应该先完成文件整理、格式统一、打印区域设置和预览检查,然后再批量打印。否则脚本跑得越快,浪费纸张也越快。

3号标题图

3. 核心原理:xlwings 的 api 与 PrintOut

  这个案例的核心代码其实只有一句:

workbook.api.PrintOut()

  但这句代码背后的含义需要讲清楚。workbook 是 xlwings 打开的工作簿对象,.api 是访问 Excel 底层 COM 对象的接口,PrintOut() 是 Excel 对象模型里的打印方法。也就是说,Python 并不是自己实现打印,而是把打印动作交给 Excel 去执行。

  xlwings 常规对象适合做读写、打开、保存等高层操作;当需要调用 Excel VBA 对象模型能力时,就要通过 .api 进入底层接口。

  这张图展示的是批量打印工作簿的核心流程:遍历文件夹、跳过临时文件、打开工作簿、调用 PrintOut 打印、最后关闭并退出。

请添加图片描述

  从图中可以看出,批量打印不是直接对整个文件夹“按一下打印”,而是逐个文件处理。脚本每次只打开一个工作簿,发送打印命令,然后关闭当前工作簿,再继续处理下一个文件。这样做的好处是流程清晰、资源占用可控,也方便定位哪个文件打印失败。

#mermaid-svg-yKT2FDX8sJxzvGDC{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-yKT2FDX8sJxzvGDC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-yKT2FDX8sJxzvGDC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-yKT2FDX8sJxzvGDC .error-icon{fill:#552222;}#mermaid-svg-yKT2FDX8sJxzvGDC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-yKT2FDX8sJxzvGDC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-yKT2FDX8sJxzvGDC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-yKT2FDX8sJxzvGDC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-yKT2FDX8sJxzvGDC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-yKT2FDX8sJxzvGDC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-yKT2FDX8sJxzvGDC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-yKT2FDX8sJxzvGDC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-yKT2FDX8sJxzvGDC .marker.cross{stroke:#333333;}#mermaid-svg-yKT2FDX8sJxzvGDC svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-yKT2FDX8sJxzvGDC p{margin:0;}#mermaid-svg-yKT2FDX8sJxzvGDC .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-yKT2FDX8sJxzvGDC .cluster-label text{fill:#333;}#mermaid-svg-yKT2FDX8sJxzvGDC .cluster-label span{color:#333;}#mermaid-svg-yKT2FDX8sJxzvGDC .cluster-label span p{background-color:transparent;}#mermaid-svg-yKT2FDX8sJxzvGDC .label text,#mermaid-svg-yKT2FDX8sJxzvGDC span{fill:#333;color:#333;}#mermaid-svg-yKT2FDX8sJxzvGDC .node rect,#mermaid-svg-yKT2FDX8sJxzvGDC .node circle,#mermaid-svg-yKT2FDX8sJxzvGDC .node ellipse,#mermaid-svg-yKT2FDX8sJxzvGDC .node polygon,#mermaid-svg-yKT2FDX8sJxzvGDC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-yKT2FDX8sJxzvGDC .rough-node .label text,#mermaid-svg-yKT2FDX8sJxzvGDC .node .label text,#mermaid-svg-yKT2FDX8sJxzvGDC .image-shape .label,#mermaid-svg-yKT2FDX8sJxzvGDC .icon-shape .label{text-anchor:middle;}#mermaid-svg-yKT2FDX8sJxzvGDC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-yKT2FDX8sJxzvGDC .rough-node .label,#mermaid-svg-yKT2FDX8sJxzvGDC .node .label,#mermaid-svg-yKT2FDX8sJxzvGDC .image-shape .label,#mermaid-svg-yKT2FDX8sJxzvGDC .icon-shape .label{text-align:center;}#mermaid-svg-yKT2FDX8sJxzvGDC .node.clickable{cursor:pointer;}#mermaid-svg-yKT2FDX8sJxzvGDC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-yKT2FDX8sJxzvGDC .arrowheadPath{fill:#333333;}#mermaid-svg-yKT2FDX8sJxzvGDC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-yKT2FDX8sJxzvGDC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-yKT2FDX8sJxzvGDC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yKT2FDX8sJxzvGDC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-yKT2FDX8sJxzvGDC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yKT2FDX8sJxzvGDC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-yKT2FDX8sJxzvGDC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-yKT2FDX8sJxzvGDC .cluster text{fill:#333;}#mermaid-svg-yKT2FDX8sJxzvGDC .cluster span{color:#333;}#mermaid-svg-yKT2FDX8sJxzvGDC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-yKT2FDX8sJxzvGDC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-yKT2FDX8sJxzvGDC rect.text{fill:none;stroke-width:0;}#mermaid-svg-yKT2FDX8sJxzvGDC .icon-shape,#mermaid-svg-yKT2FDX8sJxzvGDC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-yKT2FDX8sJxzvGDC .icon-shape p,#mermaid-svg-yKT2FDX8sJxzvGDC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-yKT2FDX8sJxzvGDC .icon-shape .label rect,#mermaid-svg-yKT2FDX8sJxzvGDC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-yKT2FDX8sJxzvGDC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-yKT2FDX8sJxzvGDC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-yKT2FDX8sJxzvGDC :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}

指定目标文件夹

遍历文件夹中的文件

是否为 Excel 临时文件

跳过该文件

是否为 Excel 工作簿

打开工作簿

调用 workbook.api.PrintOut

关闭工作簿

是否还有下一个文件

退出 Excel 应用

  这里最容易忽略的是临时文件过滤。Excel 打开工作簿时,经常会生成以 ~$ 开头的临时文件。如果脚本不跳过这些文件,就可能出现打开失败、权限异常、打印错误等问题。

4号标题图

4. 基础代码:批量打印文件夹下所有工作簿

  下面这段代码适合先理解基础流程。你只需要修改 folder_path 为自己的 Excel 文件夹路径即可。运行前建议先准备一个测试文件夹,里面只放 1 到 2 个测试工作簿。

import os
import xlwings as xw

folder_path = r"e:\\file"

app = xw.App(visible=False, add_book=False)

try:
for file_name in os.listdir(folder_path):

# 跳过 Excel 临时文件
if file_name.startswith("~$"):
continue

# 只处理 Excel 工作簿
if not file_name.lower().endswith((".xlsx", ".xls", ".xlsm")):
continue

full_path = os.path.join(folder_path, file_name)

wb = app.books.open(full_path)

# 调用 Excel 自身的打印能力
wb.api.PrintOut()

print(f"已发送打印任务:{file_name}")

wb.close()

finally:
app.quit()

  这段代码的执行顺序很明确:先启动 Excel,再遍历目标文件夹,然后筛选 Excel 文件,打开后调用 PrintOut(),最后关闭工作簿并退出 Excel。

  注意:打印是真实动作,脚本运行后会直接向打印机发送任务。不要在正式目录里第一次测试,更不要直接对几十个文件运行。稳妥做法是先用测试目录验证,再逐步扩大范围。

  推荐先把打印参数改成预览模式,确认页面、分页、页眉页脚和打印区域无误后,再改成正式打印。

wb.api.PrintOut(Preview=True)

  如果预览正常,再切换成正式打印:

wb.api.PrintOut()

5号标题图

5. PrintOut 常用参数:不要只会默认打印

  PrintOut() 可以不带参数直接打印,也可以传入一些常用参数。实际办公中,最常用的是预览、打印份数、指定页码范围和指定打印机。

参数作用示例
From 从第几页开始打印 From=1
To 打印到第几页 To=2
Copies 打印份数 Copies=2
Preview 是否先预览 Preview=True
ActivePrinter 指定打印机 ActivePrinter=“Microsoft Print to PDF”
Collate 是否逐份打印 Collate=True

  最基础的直接打印如下:

wb.api.PrintOut()

  测试阶段建议使用预览:

wb.api.PrintOut(Preview=True)

  如果要打印两份,可以这样写:

wb.api.PrintOut(Copies=2)

  如果只打印第一页,可以这样写:

wb.api.PrintOut(From=1, To=1)

  指定打印机时要特别小心。在 Excel 自动化里,打印机名称不一定只看 Windows 设置里显示的短名称,有时需要匹配 Excel 当前识别到的完整打印机字符串。企业环境里如果存在共享打印机、漫游打印、Follow-Me Print 或打印服务器,打印机名称不一致就可能导致打印失败。

  可以先输出当前 Excel 识别到的默认打印机:

print(app.api.ActivePrinter)

  确认名称后,再考虑指定打印机:

wb.api.PrintOut(ActivePrinter=app.api.ActivePrinter)

  我的建议是:除非明确知道打印机名称,否则先使用默认打印机测试,不要一上来就硬指定打印机。

6号标题图

6. 进阶场景:只批量打印指定工作表

  有些工作簿里包含多张表,比如 明细、数据、汇总、说明。实际打印时,可能只需要打印 汇总 这一张表。如果直接对整个工作簿调用 workbook.api.PrintOut(),就可能把不该打印的工作表也一起打出来。

  这种情况下,正确思路不是打印整个工作簿,而是先定位目标工作表,再对工作表调用 PrintOut。

  这张图展示的是“指定工作表打印”的逻辑:多个工作簿中只定位并打印 汇总 工作表,不打印其他工作表。

请添加图片描述

  从图中可以看出,指定工作表打印比批量打印整个工作簿多了一个判断动作:检查当前工作簿里是否存在目标工作表。如果存在,就打印该工作表;如果不存在,就跳过并记录提示。这一步很重要,否则脚本遇到缺少 汇总 表的文件就会直接报错。

import os
import xlwings as xw

folder_path = r"e:\\file"
target_sheet = "汇总"

app = xw.App(visible=False, add_book=False)

try:
for file_name in os.listdir(folder_path):

if file_name.startswith("~$"):
continue

if not file_name.lower().endswith((".xlsx", ".xls", ".xlsm")):
continue

full_path = os.path.join(folder_path, file_name)
wb = app.books.open(full_path)

sheet_names = [sheet.name for sheet in wb.sheets]

if target_sheet not in sheet_names:
print(f"跳过:{file_name},不存在工作表:{target_sheet}")
wb.close()
continue

sheet = wb.sheets[target_sheet]

# 只打印指定工作表
sheet.api.PrintOut()

print(f"已打印:{file_name} -> {target_sheet}")

wb.close()

finally:
app.quit()

  这段代码比直接打印工作簿更适合真实办公场景,因为它控制了打印范围。尤其是报表类文件,很多时候明细数据不应该打印,真正需要输出的只是汇总页、封面页或审批页。

  不要默认认为整个工作簿都适合打印。自动化不是盲目执行,而是要把业务规则写进脚本里。

7号标题图

7. 打印前检查:批量打印最怕“错得很快”

  批量打印和批量修改文件不一样。批量修改出错,还可以用备份恢复;批量打印出错,可能已经浪费了纸张、墨粉和时间,严重一点还可能把不该打印的内容输出到共享打印机上。

  所以批量打印必须先做检查,再正式运行。这里不要偷懒。自动化脚本越快,错误扩散也越快。

  这张图展示的是批量打印前最关键的检查项:先用预览测试、跳过临时文件、检查打印机名称、确认打印区域。

请添加图片描述

  从图中可以看出,真正稳定的批量打印流程,不是写完 PrintOut() 就结束,而是要先预览、再确认、最后批量打印。尤其在企业办公环境里,打印机可能是共享设备,也可能带权限控制,还可能存在离线、缺纸、卡纸、驱动弹窗等情况。

  第一个检查点是 先用预览测试。建议先对一个文件使用 Preview=True,检查页眉页脚、分页、纸张方向和内容完整性。

wb.api.PrintOut(Preview=True)

  第二个检查点是 跳过临时文件。Excel 临时文件通常以 ~$ 开头,这类文件不能当作正常工作簿处理。

if file_name.startswith("~$"):
continue

  第三个检查点是 检查打印机名称。尤其是使用共享打印机时,要确认默认打印机是否正确。否则脚本没有报错,但文件可能被发到了错误设备。

print(app.api.ActivePrinter)

  第四个检查点是 确认打印区域。Excel 的打印输出会受到页面布局、缩放比例、打印区域、纸张方向影响。脚本触发打印,不代表它会自动帮你排版。

  PrintOut 负责执行打印动作,但打印效果取决于工作簿本身的页面设置。这个边界必须分清楚。

8号标题图

8. 更稳的版本:加入日志与异常处理

  如果只是学习,可以使用基础版本;但如果真的要在办公环境里使用,我建议至少加上日志和异常处理。原因很直接:一旦某个文件打印失败,你需要知道是哪一个文件失败,而不是只看到脚本中断。

  下面这版代码会逐个处理文件,并且记录成功和失败情况。它不算复杂,但比裸跑 PrintOut() 更适合实际使用。

import os
import xlwings as xw

folder_path = r"e:\\file"
log_path = os.path.join(folder_path, "print_log.txt")

app = xw.App(visible=False, add_book=False)

success_count = 0
fail_count = 0

try:
with open(log_path, "w", encoding="utf-8") as log:

for file_name in os.listdir(folder_path):

if file_name.startswith("~$"):
continue

if not file_name.lower().endswith((".xlsx", ".xls", ".xlsm")):
continue

full_path = os.path.join(folder_path, file_name)
wb = None

try:
wb = app.books.open(full_path)

# 测试阶段建议先使用 Preview=True
wb.api.PrintOut()

success_count += 1
msg = f"成功发送打印任务:{file_name}"
print(msg)
log.write(msg + "\\n")

except Exception as e:
fail_count += 1
msg = f"打印失败:{file_name},原因:{e}"
print(msg)
log.write(msg + "\\n")

finally:
if wb is not None:
wb.close()

summary = f"打印任务结束:成功 {success_count} 个,失败 {fail_count} 个"
print(summary)
log.write(summary + "\\n")

finally:
app.quit()

  这个版本的价值在于可复盘。脚本执行完以后,不仅知道“跑完了”,还知道哪些文件成功、哪些文件失败、失败原因是什么。办公自动化脚本如果不能复盘,出了问题就很难解释。

  不过要注意,日志只能记录脚本层面的异常,不能完全证明打印机已经成功出纸。比如打印任务已经发送,但打印机缺纸、卡纸、脱机,这些属于打印设备层面的问题,需要结合打印队列和设备状态确认。

9号标题图

9. 效果验证:脚本跑完后应该看什么

  批量打印完成后,不要只看 Python 控制台输出。至少要从三个层面验证:脚本层、打印队列层、纸质输出层。

  脚本层面,查看控制台或日志,确认处理了多少个文件,成功多少个,失败多少个。这个结果能判断脚本有没有完整遍历目标目录。

  打印队列层面,检查 Windows 打印队列是否还有任务阻塞。如果队列里有大量“正在打印”或“错误”状态,就说明问题不在代码本身,而可能在打印机、驱动、网络或权限。

  纸质输出层面,抽查打印结果。重点看是否漏页、是否分页错误、是否缩放异常、是否打印了不该打印的工作表。

  办公自动化脚本的验证标准不是“程序没报错”,而是“业务结果正确”。批量打印尤其如此,因为它涉及真实设备输出,不能只停留在代码层面。

  我建议正式使用时采用这个顺序:先选 1 个文件预览,再选 2 到 3 个文件试打,最后再对完整目录批量执行。这样虽然多一步,但风险低很多。

10号标题图

10. 总结提升:批量打印不是炫技,是流程标准化

  这一节的核心不是记住 workbook.api.PrintOut() 这一句,而是理解批量打印背后的自动化流程。一个成熟的脚本,应该完成文件筛选、工作簿打开、打印动作、异常处理、资源释放和结果记录。

  真正值得沉淀的不是某一段代码,而是一套稳定的办公处理习惯。

  第一,批量打印前要先确认文件范围。不要把临时文件、无关文件、测试文件混在同一个目录里。

  第二,正式打印前要先预览。尤其是页眉页脚、分页、缩放比例、纸张方向,这些问题脚本不会自动替你判断。

  第三,能打印指定工作表,就不要盲目打印整个工作簿。很多报表真正需要输出的是 汇总、封面 或 审批页,而不是全部明细。

  第四,脚本要及时关闭工作簿并退出 Excel。否则后台 Excel 进程残留,后续可能引发文件占用、保存失败、打印异常。

  批量打印最怕的不是慢,而是没有确认就快速出错。所以这类脚本一定要遵循“先预览、再确认、后批量”的原则。

  通过这一节,我对 Excel 自动化又多了一层理解:Python 不只是用来处理数据,也可以把 Excel 的界面操作、打印操作、办公流程串起来。只要规则清楚,重复动作就应该尽量脚本化;但只要涉及真实输出,就必须加上验证和回退意识。


请添加图片描述

🔝 返回顶部

点击回到顶部

赞(0)
未经允许不得转载:171主机测评 » 《超简单:用 Python 让 Excel 飞起来》读书笔记:第4章 案例06 批量打印工作簿
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址