吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2147|回复: 2
收起左侧

[Python 原创] gpt写的小工具----邮件合并

[复制链接]
li916811602 发表于 2023-8-18 16:52
其实就是word的邮件合并功能,费了挺大力气搞得,也不知道工作是变得方便了还是复杂了。
想要写的功能还很多,一点一点来吧。
1、邮件合并功能
有时间会写的功能,希望有需要的人可以一起参与进来。接下来可能会写的功能:
2、提取word中的关键字生成邮件合并功能中的表格。
3、编写一个PDF合并、拆分、转换的工具。
4、excel合并、拆分的工具。
5、word合并、拆分的工具。
6、文件清理、及整理工具。
7、文件及文件夹变化监控工具。
8、如果有能力的话,将上面的小工具整合在一起形成一个资料员管理资料的工具箱。
任重道远,随时跑路。


import sys
import os
import pandas as pd
import datetime
import time
import shutil
import openpyxl
from docxtpl import DocxTemplate
from docx import Document
import os.path
from docx2python import docx2python
from openpyxl import load_workbook
import win32com.client as win32
from PyQt5 import QtCore, QtGui, QtWidgets

import tkinter
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox

# 新建过程文件夹
def create_process_folders():
    """新建过程文件夹及子文件夹,返回过程文件夹路径与四个子文件夹路径"""
    # 过程文件夹路径
    new_root_dir = os.path.join(os.getcwd(), '过程文件夹')

    # 若文件夹存在,删除重建
    if os.path.exists(new_root_dir):
        shutil.rmtree(new_root_dir)
    os.mkdir(new_root_dir)

    # 逐份文件夹
    new_separate_dir = os.path.join(new_root_dir, '逐份文件')
    os.mkdir(new_separate_dir)

    # 合并文件文件夹
    new_merged_dir = os.path.join(new_root_dir, '合并文件')
    os.mkdir(new_merged_dir)

    # 返回过程文件夹路径与四个子文件夹路径
    print("过程文件夹生成完毕")
    return new_root_dir,  new_separate_dir, new_merged_dir

# 将excel文件插入到word并逐行生成文件
def merge_word_template_with_excel_table(template_path, table_path, sheet_name, new_separate_dir, filename_column):
    """
    使用docx模板和数据替换模板变量,生成新文档
    """
    print("开始将excel内容写入word模板...")

    print(template_path, table_path, sheet_name, new_separate_dir, filename_column)

    # 读取excel数据
    df = pd.read_excel(table_path, sheet_name)

    # 读取word模板
    tpl = DocxTemplate(template_path)

    # 遍历表格中每一行数据,渲染模板
    for idx, row in df.iterrows():
        context = row.to_dict()
        tpl.render(context)

        # 获取文件名
        filename = f"{idx + 1}_{row[filename_column]}.docx"
        save_path = os.path.join(new_separate_dir, filename)

        # 保存新的文档
        tpl.save(save_path)
        print(save_path)
    print("excel内容逐行插入word已完成。")

# 将逐行生成的文件合并为一个文件
def merge_word_documents(new_separate_dir, output_path,add_page_break=True, template_path=None):
    """
    读取指定目录下的多个 Word 文档,将它们合并成一个新的 Word 文档。
    :param new_separate_dir: 包含 Word 文档的目录路径。
    :param add_page_break: 是否在每个文档的末尾添加分页符,默认为 True。
    :param template_path: 模板文件路径,用于设置新文档的格式与样式。
    :param output_path: 最终文件输出路径
    """
    # 获取指定路径下的所有 Word 文档
    docx_paths = [os.path.join(new_separate_dir, f) for f in os.listdir(new_separate_dir)
                  if os.path.isfile(os.path.join(new_separate_dir, f))
                  and f.endswith('.docx')]

    # 读取模板文件
    if template_path:
        template_doc = Document(template_path)

        # 获取模板文件名
        template_name = os.path.splitext(os.path.basename(template_path))[0]

        # 将模板文件名和当前时间拼接为新文件名
        new_docx_name = f"{template_name}_{datetime.datetime.now().strftime('%Y%m%d_%H%M%S')}.docx"
    else:
        template_doc = None

        # 修改生成的文件名为“原文件名称+当前时间”
        file_name = os.path.splitext(os.path.basename(docx_paths[0]))[0]
        new_docx_name = file_name + datetime.datetime.now().strftime("_%Y%m%d_%H%M%S") + '.docx'

    # 读取第一个 Word 文档
    doc = Document(docx_paths[0])

    # 如果需要在每个文档末尾添加分页符,则在第一个文档中添加分页符
    if add_page_break:
        doc.add_page_break()

    # 遍历所有文件
    for index, path in enumerate(docx_paths[1:]):
        # 读取当前文档
        current_doc = Document(path)

        # 如果需要在每个文档末尾添加分页符:
        if add_page_break:
            # 判断当前文档是否为最后一个文档
            if index == len(docx_paths) - 2:
                # 如果是最后一个文档,则不需要添加分页符
                pass
            else:
                # 在当前文档最后添加分页符
                current_doc.add_page_break()

        # 将当前文档的所有元素添加到第一个文档中
        for element in current_doc.element.body:
            doc.element.body.append(element)

    # 将第一个文档保存到指定路径
    new_docx_path = os.path.join(output_path, new_docx_name)
    print("我就看看是不是这里")
    print(new_docx_path)
    doc.save(new_docx_path)
    print("文件生成完毕并已合并完成")

#移动位置
def move_files_to_output(new_separate_dir, output_dir):
    """
    将new_separate_dir文件夹下的所有文件移动到output_dir指定的输出文件夹中,并处理重复文件
    :param new_separate_dir: 文件源文件夹路径
    :param output_dir: 输出文件夹路径
    :return: None
    """
    files = os.listdir(new_separate_dir)
    duplicate_files = []  # 存储重复文件路径

    for file in files:
        if os.path.exists(os.path.join(output_dir, file)):
            option = messagebox.askquestion(title='文件重复',
                                            message=f'目标文件夹中已存在{file},请选择操作方式:',
                                            icon='warning')
            if option == 'skip':  # 跳过
                duplicate_files.append(file)
                print(f'跳过{file}')
                continue
            elif option == 'overwrite':  # 覆盖
                shutil.move(os.path.join(new_separate_dir, file), os.path.join(output_dir, file))
                print(f"{file} 被覆盖")
            elif option == 'rename':  # 重命名
                file_name, ext = os.path.splitext(file)
                new_name = f"{file_name}_{time.strftime('%Y%m%d%H%M%S')}{ext}"
                shutil.move(os.path.join(new_separate_dir, file), os.path.join(output_dir, new_name))
                print(f"{file} 重命名为 {new_name}")
        else:
            shutil.move(os.path.join(new_separate_dir, file), os.path.join(output_dir, file))

    if duplicate_files:  # 存在跳过的重复文件
        option = messagebox.askquestion(title='重复文件跳过提示',
                                        message=f'存在{len(duplicate_files)}个重复文件被跳过,请选择后续操作:',
                                        icon='warning')
        if option == 'yes':  # 删除跳过的重复文件
            for file in duplicate_files:
                os.remove(os.path.join(new_separate_dir, file))
        else:  # 保留跳过的重复文件
            pass
    print("已降落,是不是速度太快,都没有看清楚。")

# 主函数
def generate_report(template_path, table_path, sheet_name, output_dir,filename_column,
                    merge=False, add_page_break=True):
    """
    生成Word报表
    :param template_path: Word模板文件路径
    :param table_path: Excel数据文件路径
    :param sheet_name: Excel工作表名称
    :param output_dir: 报表输出目录
    :param merge: 是否合并生成的Word文件
    :param add_page_break: 合并文件时是否添加分页符
    """
    # 生成文件夹
    new_root_dir, new_separate_dir, new_merged_dir = create_process_folders()

    # 将Excel数据合并到模板,生成Word文件
    merge_word_template_with_excel_table(template_path, table_path, sheet_name, new_separate_dir, filename_column)

    # 移动或合并Word文件
    if not merge:
        move_files_to_output(new_separate_dir, output_dir)
    else:
        merge_word_documents(new_separate_dir, output_dir, add_page_break, template_path)

    # 删除临时文件夹
    shutil.rmtree(new_root_dir)

class ExcelSelector(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()

        # 创建控件并设置属性和布局
        self.browse_excel_button = QtWidgets.QPushButton("浏览Excel文件")
        self.browse_word_button = QtWidgets.QPushButton("浏览Word模板文件")

        self.browse_excel_button.clicked.connect(self.browse_excel_file)
        self.browse_word_button.clicked.connect(self.browse_word_file)

        self.excel_path_line_edit = QtWidgets.QLineEdit()
        self.word_path_line_edit = QtWidgets.QLineEdit()
        self.output_dir_line_edit = QtWidgets.QLineEdit()

        self.sheet_combo_box = QtWidgets.QComboBox()
        self.column_combo_box = QtWidgets.QComboBox()

        self.merge_checkbox = QtWidgets.QCheckBox("合并单元格")
        self.insert_page_break_checkbox = QtWidgets.QCheckBox("插入分页符")
        self.merge_checkbox.setChecked(True)
        self.insert_page_break_checkbox.setChecked(True)

        self.generate_word_file_button = QtWidgets.QPushButton("生成Word文件")
        self.generate_word_file_button.clicked.connect(self.generate_word_file)

        # 添加输出文件夹选择相关控件和布局
        self.output_dir_button = QtWidgets.QPushButton("选择输出文件夹")
        self.output_dir_button.clicked.connect(self.browse_output_dir)

        self.merge_checkbox.clicked.connect(self.toggle_column_selection)

        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.browse_excel_button)
        layout.addWidget(self.excel_path_line_edit)
        layout.addWidget(self.sheet_combo_box)
        layout.addWidget(self.column_combo_box)
        layout.addWidget(self.browse_word_button)
        layout.addWidget(self.word_path_line_edit)
        layout.addWidget(self.merge_checkbox)
        layout.addWidget(self.insert_page_break_checkbox)
        layout.addWidget(QtWidgets.QLabel("输出文件夹"))
        self.output_dir_layout = QtWidgets.QHBoxLayout()
        self.output_dir_layout.addWidget(self.output_dir_line_edit)
        self.output_dir_layout.addWidget(self.output_dir_button)
        layout.addLayout(self.output_dir_layout)
        layout.addWidget(self.generate_word_file_button)
        self.setLayout(layout)

    def browse_excel_file(self):
        # 打开文件浏览器
        options = QtWidgets.QFileDialog.Options()
        file_name, _ = QtWidgets.QFileDialog.getOpenFileName(
            self,
            "选择Excel文件",
            "",
            "Excel Files (*.xls *.xlsx *.csv)",
            options=options
        )

        if file_name:
            # 更新类成员变量中的 Excel 文件路径
            self.excel_path = file_name
            self.excel_path_line_edit.setText(self.excel_path)

            # 调用函数更新下拉框
            self.update_sheet_combo_box()

    def update_sheet_combo_box(self):
        # 获取当前选定的 Excel 文件的工作表名称
        sheet_names = self.get_sheet_names(self.excel_path)
        self.sheet_combo_box.clear()
        self.sheet_combo_box.addItems(sheet_names)

        # 更新列名下拉框
        self.update_column_combo_box()

    def update_column_combo_box(self):
        # 重置列名下拉框
        self.column_combo_box.clear()

        # 获取选定的工作表和该工作表的首行数据
        sheet_name = self.sheet_combo_box.currentText()
        first_row = self.get_first_row(self.excel_path, sheet_name)

        # 将首行中每一列的列名添加到列名下拉框中,并为每个列名增加一个自定义属性,其值为该列所对应的数字
        for i, column in enumerate(first_row):
            self.column_combo_box.addItem(str(column), userData=i)

    def get_sheet_names(self, file_name):
        if file_name.endswith(".xls") or file_name.endswith(".xlsx") or file_name.endswith(".csv"):
            df = pd.read_excel(file_name, None)
            return list(df.keys())
        else:
            return []

    def get_first_row(self, file_name, sheet_name):
        df = pd.read_excel(file_name, sheet_name)
        return df.columns.tolist()

    def browse_word_file(self):
        # 打开文件浏览器
        options = QtWidgets.QFileDialog.Options()
        file_name, _ = QtWidgets.QFileDialog.getOpenFileName(
            self,
            "选择Word模板文件",
            "",
            "Word Files (*.doc *.docx)",
            options=options
        )

        if file_name:
            # 更新类成员变量中的 Word 文件路径
            self.word_path = file_name
            self.word_path_line_edit.setText(self.word_path)

    def browse_output_dir(self):
        # 打开文件夹浏览器
        dir_name = QtWidgets.QFileDialog.getExistingDirectory(
            self,
            "选择输出文件夹",
            "",
            QtWidgets.QFileDialog.ShowDirsOnly | QtWidgets.QFileDialog.DontResolveSymlinks
        )

        if dir_name:
            # 更新类成员变量中的输出文件夹路径
            self.output_dir = dir_name
            self.output_dir_line_edit.setText(self.output_dir)

    def toggle_column_selection(self):
        if self.merge_checkbox.isChecked():
                # 合并单元格被选中,隐藏列内容选择框
            self.column_combo_box.hide()
            self.insert_page_break_checkbox.show()

        else:
            # 合并单元格未被选中,隐藏插入分页符
            self.column_combo_box.show()
            self.insert_page_break_checkbox.hide()

    def generate_word_file(self):
        template_path = self.word_path
        table_path = self.excel_path
        sheet_name = self.sheet_combo_box.currentText()
        filename_column = self.column_combo_box.currentData()
        merge = self.merge_checkbox.isChecked()
        add_page_break = self.insert_page_break_checkbox.isChecked()
        output_dir = self.output_dir
        print("界面内容读取完毕")
        generate_report(template_path, table_path, sheet_name, output_dir, filename_column = filename_column,
                            merge = merge, add_page_break = add_page_break)

if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)
    excel_selector = ExcelSelector()
    excel_selector.show()
    sys.exit(app.exec_())

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

zb105634 发表于 2023-8-21 16:16
6666666666
Superwill8216 发表于 2023-11-23 07:53
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-24 17:19

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表