用Python的win32api库,WPS文档自动化生成技巧!

举报
忆愿 发表于 2025/02/13 12:52:29 2025/02/13
117 0 0
【摘要】 你好,我是忆~遂愿,全网4w+粉丝,《遂愿盈创》社群主理人。副业启航① | 遂愿盈创(对副业感兴趣免费可入,多种赚钱实战项目等你来,一起探寻副业快速变现的途径;以及对接互联网大厂商务合作,一起来搞点小外快,认识更多互联网大咖)目前群里已经带很多小伙伴(大部分大学生)变现几百块啦,程序员搞副业有额外加成~ 对副业感兴趣可+V : suiyuan2ying 拉你进群。在办公室搬砖的日子里,天天要...

在这里插入图片描述

你好,我是忆~遂愿,全网4w+粉丝,《遂愿盈创》社群主理人。
副业启航① | 遂愿盈创(对副业感兴趣免费可入,多种赚钱实战项目等你来,一起探寻副业快速变现的途径;以及对接互联网大厂商务合作,一起来搞点小外快,认识更多互联网大咖)
目前群里已经带很多小伙伴(大部分大学生)变现几百块啦,程序员搞副业有额外加成~ 对副业感兴趣可+V : suiyuan2ying 拉你进群。

在办公室搬砖的日子里,天天要写各种文档报告,复制粘贴改来改去,烦都烦死了。

每次都是打开Word,找模板,改内容,调格式,一天下来手都快点麻了。

最烦的是改完一份,还有一堆在等着,而且总会不小心改错几个地方。

直到我发现了Python的win32api库,这简直就是救命稻草啊!一个脚本搞定文档生成,不光省时间,还特别准确。

写好模板,准备好数据,一键运行就完事了,再也不用担心改错或者漏改了。

说实话,我一开始也没想到Python还能这么玩。

总觉得写文档这种事情,不就是复制粘贴吗?谁知道用代码来处理,不仅效率高得吓人,而且准确度简直完美。

要不是那天加班到半夜,实在受不了无止境的文档修改,也不会想到用代码来解放双手。

记得那天改到眼睛都花了,突然灵光一闪:这种重复性的工作,不就是最适合用代码来处理的吗?

现在好了,一杯咖啡的功夫,几百份文档就搞定了,老板都以为我加班到很晚呢!

最关键的是,代码生成的文档格式统一,内容准确,质量反而比手工做的更好。这下不仅省了时间,还收获了老板的赞赏,简直是一举两得!

win32api是啥玩意?

说白了,win32api就是个能操控Windows程序的Python库。

它就像是个神奇的遥控器,能让Python代码直接控制Windows上的各种应用程序,包括Word、Excel、PowerPoint等办公软件。

它能直接跟WPS对话,就像你在用鼠标键盘操作一样。

比如你想打开一个Word文档,修改内容,调整格式,保存文件,这些都能用代码来完成,而且速度比手动操作快多了。

装这个库超简单,一行命令就搞定:

pip install pywin32

不过得注意啊,电脑上得先装好WPS或者Office,不然这代码就跑不起来了。

因为win32api本质上是在模拟你操作这些软件,没有安装相应的软件,代码自然就无处施展了。

还有个事儿,装完之后最好重启一下电脑,不然有时候会莫名其妙报错。

这是因为win32api需要在系统层面注册一些组件,重启能确保这些组件都正确加载了。

使用win32api的好处是,它能完美兼容现有的办公软件,你之前的文档模板都能继续用,不用改来改去。

而且它的操作特别灵活,几乎所有你能手动完成的操作,都能用代码来实现。对于需要批量处理文档的人来说,这简直就是办公自动化的利器!

连接WPS的魔法

来看看怎么跟WPS搭上线:

import win32com.client
import os
import time
from typing import Optional, Dict, List

class WPSConnection:
    def __init__(self):
        self.wps = None
        self.doc = None
        
    def connect(self) -> bool:
        """建立与WPS的连接"""
        try:
            self.wps = win32com.client.Dispatch('KWps.Application')
            self.wps.Visible = True
            print('WPS连接成功!')
            return True
        except Exception as e:
            print(f'连接WPS失败:{str(e)}')
            return False
            
    def create_new_doc(self) -> bool:
        """创建新文档"""
        try:
            self.doc = self.wps.Documents.Add()
            return True
        except Exception as e:
            print(f'创建文档失败:{str(e)}')
            return False
            
    def open_doc(self, path: str) -> bool:
        """打开现有文档"""
        try:
            self.doc = self.wps.Documents.Open(path)
            return True
        except Exception as e:
            print(f'打开文档失败:{str(e)}')
            return False
            
    def close(self):
        """关闭连接"""
        if self.doc:
            self.doc.Close()
        if self.wps:
            self.wps.Quit()

温馨提示:要是报错说找不到KWps.Application,把KWps改成Word试试,有些版本用这个。

文档生成大法

整个文档生成的过程,说复杂也不复杂。咱们先从简单的开始:

class DocumentGenerator:
    def __init__(self):
        self.wps_conn = WPSConnection()
        
    def generate_simple_doc(self, title: str, content: str, save_path: str) -> bool:
        """生成简单文档"""
        if not self.wps_conn.connect():
            return False
            
        try:
            if not self.wps_conn.create_new_doc():
                return False
                
            selection = self.wps_conn.wps.Selection
            
            # 写入标题
            selection.TypeText(title)
            selection.Font.Size = 16
            selection.Font.Bold = True
            selection.TypeParagraph()
            
            # 写入正文
            selection.TypeText(content)
            selection.Font.Size = 12
            selection.Font.Bold = False
            
            # 保存文档
            self.wps_conn.doc.SaveAs(save_path)
            return True
            
        except Exception as e:
            print(f'生成文档时出错:{str(e)}')
            return False
            
        finally:
            self.wps_conn.close()

这就是最基础的文档生成了。但是实际工作中,咱们往往需要更复杂的操作,比如:

花式玩法

来点进阶操作,看看怎么玩出花样:

class AdvancedDocumentGenerator:
    def __init__(self):
        self.wps_conn = WPSConnection()
        
    def create_fancy_doc(self, config: Dict) -> bool:
        """创建花里胡哨的文档"""
        if not self.wps_conn.connect():
            return False
            
        try:
            if not self.wps_conn.create_new_doc():
                return False
                
            doc = self.wps_conn.doc
            selection = self.wps_conn.wps.Selection
            
            # 设置页面格式
            doc.PageSetup.TopMargin = 72  # 1英寸
            doc.PageSetup.BottomMargin = 72
            doc.PageSetup.LeftMargin = 72
            doc.PageSetup.RightMargin = 72
            
            # 添加页眉
            if config.get('header'):
                header = doc.Sections(1).Headers(1)
                header.Range.Text = config['header']
                header.Range.Font.Size = 10
                
            # 添加标题
            selection.TypeText(config['title'])
            selection.Font.Size = 20
            selection.Font.Bold = True
            selection.ParagraphFormat.Alignment = 1  # 居中
            selection.TypeParagraph()
            
            # 添加副标题
            if config.get('subtitle'):
                selection.TypeText(config['subtitle'])
                selection.Font.Size = 14
                selection.Font.Bold = True
                selection.ParagraphFormat.Alignment = 1
                selection.TypeParagraph()
                
            # 添加正文
            for paragraph in config['content']:
                selection.TypeText(paragraph)
                selection.Font.Size = 12
                selection.Font.Bold = False
                selection.ParagraphFormat.Alignment = 0  # 左对齐
                selection.TypeParagraph()
                
            # 插入表格
            if config.get('table_data'):
                table_data = config['table_data']
                table = doc.Tables.Add(selection.Range, 
                                     len(table_data), 
                                     len(table_data[0]))
                table.Borders.Enable = True
                
                for i, row in enumerate(table_data):
                    for j, cell_value in enumerate(row):
                        table.Cell(i+1, j+1).Range.Text = str(cell_value)
                
                selection.TypeParagraph()
                
            # 插入图片
            if config.get('images'):
                for img_path in config['images']:
                    if self._check_image(img_path):
                        doc.InlineShapes.AddPicture(img_path)
                        selection.TypeParagraph()
                        
            # 添加页脚
            if config.get('footer'):
                footer = doc.Sections(1).Footers(1)
                footer.Range.Text = config['footer']
                footer.Range.Font.Size = 10
                
            # 保存文档
            doc.SaveAs(config['save_path'])
            return True
            
        except Exception as e:
            print(f'生成高级文档时出错:{str(e)}')
            return False
            
        finally:
            self.wps_conn.close()
            
    def _check_image(self, image_path: str) -> bool:
        """检查图片是否合法"""
        allowed_formats = ['.png', '.jpg', '.jpeg']
        try:
            file_size = os.path.getsize(image_path) / (1024 * 1024)
            
            if not any(image_path.lower().endswith(fmt) for fmt in allowed_formats):
                print(f'图片 {image_path} 格式不支持')
                return False
                
            if file_size > 5:
                print(f'图片 {image_path} 太大了({file_size:.2f}MB)')
                return False
                
            return True
            
        except Exception as e:
            print(f'检查图片时出错:{str(e)}')
            return False

自动化报表生成

办公室最常见的就是各种报表了,来看看怎么自动化生成:

class ReportGenerator:
    def __init__(self):
        self.wps_conn = WPSConnection()
        
    def generate_weekly_report(self, 
                             week_num: int, 
                             data: Dict[str, List[str]], 
                             template_path: Optional[str] = None) -> bool:
        """生成周报"""
        if not self.wps_conn.connect():
            return False
            
        try:
            # 使用模板或创建新文档
            if template_path and os.path.exists(template_path):
                if not self.wps_conn.open_doc(template_path):
                    return False
            else:
                if not self.wps_conn.create_new_doc():
                    return False
                    
            doc = self.wps_conn.doc
            selection = self.wps_conn.wps.Selection
            
            # 优化性能
            self._optimize_performance()
            
            # 设置标题
            selection.TypeText(f'第{week_num}周工作周报')
            selection.Font.Size = 16
            selection.Font.Bold = True
            selection.ParagraphFormat.Alignment = 1
            selection.TypeParagraph()
            selection.TypeParagraph()
            
            # 工作内容
            if data.get('completed_tasks'):
                selection.TypeText('本周完成工作:')
                selection.Font.Size = 14
                selection.Font.Bold = True
                selection.TypeParagraph()
                
                for task in data['completed_tasks']:
                    selection.TypeText(f'    • {task}')
                    selection.Font.Size = 12
                    selection.Font.Bold = False
                    selection.TypeParagraph()
                    
                selection.TypeParagraph()
                
            # 下周计划
            if data.get('planned_tasks'):
                selection.TypeText('下周工作计划:')
                selection.Font.Size = 14
                selection.Font.Bold = True
                selection.TypeParagraph()
                
                for task in data['planned_tasks']:
                    selection.TypeText(f'    • {task}')
                    selection.Font.Size = 12
                    selection.Font.Bold = False
                    selection.TypeParagraph()
                    
                selection.TypeParagraph()
                
            # 问题和建议
            if data.get('issues'):
                selection.TypeText('存在的问题和建议:')
                selection.Font.Size = 14
                selection.Font.Bold = True
                selection.TypeParagraph()
                
                for issue in data['issues']:
                    selection.TypeText(f'    • {issue}')
                    selection.Font.Size = 12
                    selection.Font.Bold = False
                    selection.TypeParagraph()
                    
            # 添加签名和日期
            selection.TypeParagraph()
            selection.TypeParagraph()
            selection.TypeText('汇报人:' + data.get('reporter', ''))
            selection.TypeParagraph()
            selection.TypeText('日期:' + time.strftime('%Y-%m-%d'))
            
            # 保存文档
            save_path = os.path.join(os.getcwd(), f'周报_{week_num}.docx')
            doc.SaveAs(save_path)
            
            return True
            
        except Exception as e:
            print(f'生成周报时出错:{str(e)}')
            return False
            
        finally:
            # 恢复性能设置
            self._restore_performance()
            self.wps_conn.close()
            
    def _optimize_performance(self):
        """优化性能设置"""
        self.wps_conn.wps.ScreenUpdating = False
        self.wps_conn.wps.Options.BackgroundSave = False
        
    def _restore_performance(self):
        """恢复性能设置"""
        self.wps_conn.wps.ScreenUpdating = True
        self.wps_conn.wps.Options.BackgroundSave = True

批量处理大法

要是要处理几百份文档,一个一个来肯定不行,得上批量处理:

class BatchProcessor:
    def __init__(self):
        self.wps_conn = WPSConnection()
        
    def process_multiple_docs(self, 
                            source_folder: str, 
                            output_folder: str,
                            process_func,
                            max_workers: int = 4) -> Dict[str, int]:
        """批量处理文档"""
        from concurrent.futures import ThreadPoolExecutor
        import threading
        
        if not os.path.exists(output_folder):
            os.makedirs(output_folder)
            
        # 统计数据
        stats = {
            'success': 0,
            'failed': 0,
            'skipped': 0
        }
        stats_lock = threading.Lock()
        
        def process_single_doc(file_path: str):
            try:
                if not file_path.endswith(('.doc', '.docx')):
                    with stats_lock:
                        stats['skipped'] += 1
                    return
                    
                output_path = os.path.join(
                    output_folder,
                    f'processed_{os.path.basename(file_path)}'
                )
                
                if process_func(file_path, output_path):
                    with stats_lock:
                        stats['success'] += 1
                else:
                    with stats_lock:
                        stats['failed'] += 1
                        
            except Exception as e:
                print(f'处理文件 {file_path} 时出错:{str(e)}')
                with stats_lock:
                    stats['failed'] += 1
                    
        # 获取所有文件
        files = [
            os.path.join(source_folder, f)
            for f in os.listdir(source_folder)
            if os.path.isfile(os.path.join(source_folder, f))
        ]
        
        # 使用线程池处理
        with ThreadPoolExecutor(max_workers=max_workers) as executor:
            executor.map(process_single_doc, files)
            
        return stats

实用小工具

平时工作中经常用到的一些小功能,我都封装成了工具类:

class DocUtils:
    @staticmethod
    def convert_to_pdf(doc_path: str, pdf_path: str) -> bool:
        """转换文档为PDF"""
        try:
            wps = win32com.client.Dispatch('KWps.Application')
            doc = wps.Documents.Open(doc_path)
            doc.SaveAs(pdf_path, 17)  # 17 是 PDF 格式的代码
            doc.Close()
            wps.Quit()
            return True
        except Exception as e:
            print(f'转换PDF时出错:{str(e)}')
            return False
            
    @staticmethod
    def merge_docs(doc_paths: List[str], output_path: str) -> bool:
        """合并多个文档"""
        try:
            wps = win32com.client.Dispatch('KWps.Application')
            merged_doc = wps.Documents.Add()
            
            for doc_path in doc_paths:
                merged_doc.Application.Selection.InsertFile(doc_path)
                merged_doc.Application.Selection.InsertBreak(7)  # 分页符
                
            merged_doc.SaveAs(output_path)
            merged_doc.Close()
            wps.Quit()
            return True
        except Exception as e:
            print(f'合并文档时出错:{str(e)}')
            return False
            
    @staticmethod
    def extract_text(doc_path: str) -> str:
        """提取文档中的文本"""
        try:
            wps = win32com.client.Dispatch('KWps.Application')
            doc = wps.Documents.Open(doc_path)
            text = doc.Content.Text
            doc.Close()
            wps.Quit()
            return text
        except Exception as e:
            print(f'提取文本时出错:{str(e)}')
            return ''

使用示例

来看看怎么用这些类:

def main():
    # 生成简单文档
    gen = DocumentGenerator()
    gen.generate_simple_doc(
        title="测试文档",
        content="这是一个测试文档的内容",
        save_path="test.docx"
    )
    
    # 生成周报
    report_gen = ReportGenerator()
    report_data = {
        'completed_tasks': [
            '完成了项目A的开发',
            '修复了3个bug',
            '参加了2次技术评审'
        ],
        'planned_tasks': [
            '开始项目B的开发',
            '优化现有代码'
        ],
        'issues': [
            '服务器性能需要优化',
            '需要更多的单元测试'
        ],
        'reporter': '小忆'
    }
    report_gen.generate_weekly_report(1, report_data)
    
    # 批量处理文档
    batch = BatchProcessor()
    stats = batch.process_multiple_docs(
        'input_folder',
        'output_folder',
        lambda x, y: DocUtils.convert_to_pdf(x, y)
    )
    print(f'处理结果:{stats}')

这些代码够你玩一阵子了。记住啊,代码写完多测试,别一上来就真实数据,万一出问题就尴尬了。

自动化是好,但也得留个心眼,别把文档搞丢了。

还有个事儿,这些代码都是我实际用过的,但是不同的WPS版本可能会有点差异,用的时候记得调试一下。

要是遇到问题,就在代码里加点日志,方便排查。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。