【办公类-115-01】20260906育儿知识(家园小报)批量制作(2026年9月-2027年6月)

一、背景需求

(一)资料获取

今年我带中2班,问去年中2班(现大2班)的老师要了他们班的班级电子资料

发来的资料里面,育儿知识(家园小报)只有一个9月份的,应该每个月一份

分类整理

这个育儿知识(小报)的背景图还是很好看的

可惜只有一个月的,我不想再问大2班老师索要了,她说自己也是费力整理过的(两位老师分工写的班级电子资料,合并后难免也会有遗漏)

(二)制作思路

之前用豆包AI做了全园班级的"国旗下讲话""四大教育",展现出豆包AI编写文字的强大能力。

【办公类-146-05】20260901《一分园、二分园四大教育》(优化版:标题excle+复制AI文字+Python占位符录入)https://mp.csdn.net/mp_blog/creation/editor/164367119

【办公类-119-03】20260901三个园区"国旗下讲话" 按班级组合docx模板(AI+excel+python、deepseek和豆包、微信自动私发)https://mp.csdn.net/mp_blog/creation/editor/164123764

我想用豆包编写另外几个月家园小报的文字(表格形式),再用Python写入到word。

二、word模版制作

(根据现有的word模版制作,包含教师名字、家委会成员名字等)

(一)复制模版

(二)doc另存为docx

(三)把基础信息改成占位符

标题原来有一个特殊字体,而且是艺术字插入(可以卷曲),我现在没有这个字体,艺术字,所以还是改成普通的标题。

由于背景图在顶层,所以育儿知识几个字不好修改,改成放在文字下方

但是图片放在文字下方,还是不能编辑文字,就把图片缩小拖到别的地方,现在育儿知识(艺术字)就可以编辑了。

为了方便,我把艺术字框删除了,第一行重新做标题

第一段有370-380字

第一段改成congtent1

第二段大约350-360字

把背景图剪切,重新黏贴成图片,然后用冲蚀点中间,再把图片置于文字底部。这样文字就能够编辑了。不会被图片遮挡

三、EXCEL数据制作

(一)制作EXCEL的列标题

python 复制代码
'''
育儿知识(中2班)
excle的列标题制作(占位符字母)
豆包、Deepseek、阿夏
2026096
'''

import pandas as pd
import os
# ========== 路径配置 ==========
BASE_PATH = r'D:\Python最终内容\20260906育儿知识中2'
CLASS_NAME = "中2班"
EDU_THEME = "全部主题"
date = '20260904'
EXCEL_PATH = os.path.join(BASE_PATH, f"{date}{CLASS_NAME}育儿知识({EDU_THEME}).xlsx")
# 表头字段【已改成docx模板里面{{}}内的标识符】
columns = [
    'classroom','title','T1','T2','S',
    'parent','content1','title2','content2',
    'year', 'month'
]
def create_empty_excel_header_only():
    """只生成仅有表头的Excel,没有数据行"""
    os.makedirs(BASE_PATH, exist_ok=True)
    df = pd.DataFrame(columns=columns)
    df.to_excel(EXCEL_PATH, index=False)
    print(f"✅ 已生成仅带表头的Excel")
    print(f"📂 文件路径:{EXCEL_PATH}")
    print(f"📋 表头:{columns}")
if __name__ == "__main__":
    create_empty_excel_header_only()

(二)根据9月份的育儿知识的word模版内容,制作10份符合节日制作EXCEL的列标题。

1.第1次

点击豆包表格右上角的复制

打开EXCEL,把内容黏贴

但是每行有三段,这样无法整段写入

2.第2次:每段用aaa连接

(三)Python代码

实验代码,不要用

python 复制代码
import pandas as pd
from docxtpl import DocxTemplate
from docx import Document
from docx.enum.text import WD_BREAK
from docx.shared import Pt
from docx.oxml.ns import qn
import os
import sys
import subprocess
import zipfile
import shutil

# ========== 全局路径配置(只需修改这里) ==========
BASE_PATH = r'D:\Python最终内容\20260906育儿知识中2'
CLASS_NAME = "中2班"
EDU_THEME = "全部主题"
date = '20260904'


# ==============================================
EXCEL_PATH = os.path.join(BASE_PATH, f"{date}{CLASS_NAME}育儿知识({EDU_THEME}).xlsx")
TEMPLATE_PATH = os.path.join(BASE_PATH, "育儿知识模版.docx")
OUTPUT_FOLDER = os.path.join(BASE_PATH, f"01 ({CLASS_NAME}){EDU_THEME}_输出")
PROCESSED_FOLDER = os.path.join(BASE_PATH, f"01 ({CLASS_NAME}){EDU_THEME}_最终")
RAR_PATH = os.path.join(BASE_PATH, f"01 ({CLASS_NAME}){EDU_THEME}_最终.rar")
ZIP_PATH = os.path.join(BASE_PATH, f"01 ({CLASS_NAME}){EDU_THEME}_最终.zip")

if sys.platform == 'win32':
    import io
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')


# def step1_generate_excel():
#     """第一步:生成占位符Excel文件(字段和docx模板占位符一一对应)"""
#     print("\n" + "="*60)
#     print("第一步:生成占位符Excel文件")
#     print("="*60)
#     # 与docx模板{{}}一一对应,去掉大括号作为列名
#     df = pd.DataFrame(columns=[
#         'classroom','title','T1','T2','S','parent',
#         'content1','title2','content2','year','month'
#     ])
#     df.to_excel(EXCEL_PATH, index=False)
#     print(f"✅ Excel文件已生成:{EXCEL_PATH}")
#     print(f"📋 Excel表头:{list(df.columns)}")
#     # input('\n请先在Excel中填入AI生成的育儿内容,然后按回车键继续...')
#     return True


def step2_generate_word_from_excel():
    """第二步:根据Excel生成Word文档"""
    print("\n" + "="*60)
    print("第二步:根据Excel生成Word文档")
    print("="*60)
    os.makedirs(OUTPUT_FOLDER, exist_ok=True)
    generated_files = []

    if not os.path.exists(EXCEL_PATH):
        print(f"❌ 错误:Excel不存在 - {EXCEL_PATH}")
        return False
    if not os.path.exists(TEMPLATE_PATH):
        print(f"❌ 错误:模板文件不存在 - {TEMPLATE_PATH}")
        return False

    schedule = pd.read_excel(EXCEL_PATH)
    # 全部字段转为字符串,nan替换为空
    excel_cols = ['classroom','title','T1','T2','S','parent','content1','title2','content2','year','month']
    for col in excel_cols:
        if col in schedule.columns:
            schedule[col] = schedule[col].astype(str).replace('nan', '')

    # 设置默认值
    if 'classroom' not in schedule.columns:
        schedule['classroom'] = CLASS_NAME
    if 'T1' not in schedule.columns:
        schedule['T1'] = '王'
    if 'T2' not in schedule.columns:
        schedule['T2'] = '张'
    if 'S' not in schedule.columns:
        schedule['S'] = '张三'
    if 'parent' not in schedule.columns:
        schedule['parent'] = '妈妈'
    if 'year' not in schedule.columns:
        schedule['year'] = '2026'
    if 'month' not in schedule.columns:
        schedule['month'] = '9'

    schedule.to_excel(EXCEL_PATH, index=False)
    print(f"✅ 已保存Excel")
    print(f"📊 共有 {len(schedule)} 行数据")

    try:
        Document(TEMPLATE_PATH)
        print("✅ 模板验证通过,开始生成文档...")
    except Exception as e:
        print(f"❌ 模板无效: {e}")
        return False

    for index, row in schedule.iterrows():
        try:
            tpl = DocxTemplate(TEMPLATE_PATH)
            # 渲染上下文,完全匹配docx模板{{占位符}}
            context = {
                "classroom": str(row['classroom']) if pd.notna(row['classroom']) else CLASS_NAME,
                "title": str(row['title']) if pd.notna(row['title']) else '',
                "T1": str(row['T1']) if pd.notna(row['T1']) else '王',
                "T2": str(row['T2']) if pd.notna(row['T2']) else '张',
                "S": str(row['S']) if pd.notna(row['S']) else '张三',
                "parent": str(row['parent']) if pd.notna(row['parent']) else '妈妈',
                "content1": str(row['content1']) if pd.notna(row['content1']) else '',
                "title2": str(row['title2']) if pd.notna(row['title2']) else '',
                "content2": str(row['content2']) if pd.notna(row['content2']) else '',
                "year": str(row['year']) if pd.notna(row['year']) else '2026',
                "month": str(row['month']) if pd.notna(row['month']) else '9',
            }
            tpl.render(context)
            temp_path = os.path.join(OUTPUT_FOLDER, f"temp_{index}.docx")
            tpl.save(temp_path)
            doc = Document(temp_path)

            # ========== 修改这里:文件名:"年月"育儿知识(标题名称) ==========
            month_str = str(row['month']) if pd.notna(row['month']) else str(index+1)
            year_str = str(row['year']) if pd.notna(row['year']) else '2026'
            title_short = str(row['title'])[:18] if pd.notna(row['title']) else '育儿知识'
            filename = f"{year_str}.{month_str} 育儿知识({title_short}).docx"
            # =============================================================

            file_full_path = os.path.join(OUTPUT_FOLDER, filename)
            doc.save(file_full_path)

            if os.path.exists(temp_path):
                os.remove(temp_path)
            generated_files.append(file_full_path)
            print(f"✅ 生成文档: {filename}")
        except Exception as e:
            print(f"❌ 生成第{index+1}行文档失败: {str(e)}")
            import traceback
            traceback.print_exc()
            continue

    print(f"\n📊 文档生成完成!共生成 {len(generated_files)} 个文档")
    print(f"📂 输出目录: {OUTPUT_FOLDER}")
    return True


def process_word_document(input_path, output_path):
    """处理单个Word文档:全文段落aaa替换为手动换行符WD_BREAK.LINE"""
    try:
        doc = Document(input_path)
        modified = False

        # 遍历文档所有段落,处理aaa分隔符
        for para in doc.paragraphs:
            if 'aaa' in para.text:
                runs_info = []
                for run in para.runs:
                    runs_info.append({
                        'text': run.text,
                        'bold': run.bold,
                        'italic': run.italic,
                        'underline': run.underline,
                        'font_name': run.font.name,
                        'font_size': run.font.size,
                        'color': run.font.color.rgb if run.font.color else None
                    })
                full_text = para.text
                parts = full_text.split('aaa')
                para.clear()
                for i, part in enumerate(parts):
                    if part.strip():
                        run = para.add_run(part)
                        if runs_info:
                            run.bold = runs_info[0]['bold']
                            run.italic = runs_info[0]['italic']
                            run.underline = runs_info[0]['underline']
                            if runs_info[0]['font_name']:
                                run.font.name = runs_info[0]['font_name']
                                run._element.rPr.rFonts.set(qn('w:eastAsia'), runs_info[0]['font_name'])
                            if runs_info[0]['font_size']:
                                run.font.size = runs_info[0]['font_size']
                            if runs_info[0]['color']:
                                run.font.color.rgb = runs_info[0]['color']
                        # 添加手动换行符
                        if i < len(parts) - 1:
                            para.add_run().add_break(WD_BREAK.LINE)
                modified = True

        doc.save(output_path)
        if os.path.exists(output_path):
            return True, modified
        else:
            return False, False
    except Exception as e:
        print(f"    错误: {str(e)}")
        import traceback
        traceback.print_exc()
        return False, False


def step3_process_documents():
    """第三步:批量处理Word文档"""
    print("\n" + "="*60)
    print("第三步:处理Word文档(aaa转手动换行符)")
    print("="*60)
    os.makedirs(PROCESSED_FOLDER, exist_ok=True)
    print(f"输入文件夹: {OUTPUT_FOLDER}")
    print(f"输出文件夹: {PROCESSED_FOLDER}")
    print("-" * 60)

    if not os.path.exists(OUTPUT_FOLDER):
        print(f"❌ 错误: 输入文件夹不存在!")
        return False

    docx_files = [f for f in os.listdir(OUTPUT_FOLDER) if f.lower().endswith('.docx')]
    if not docx_files:
        print(f"⚠️ 没有找到docx文件!")
        return False

    print(f"\n✅ 找到 {len(docx_files)} 个docx文件")
    print("-" * 60)
    success = 0
    for i, filename in enumerate(docx_files, 1):
        print(f"[{i}/{len(docx_files)}] {filename}")
        input_path = os.path.join(OUTPUT_FOLDER, filename)
        output_filename = filename
        output_path = os.path.join(PROCESSED_FOLDER, output_filename)
        result, modified = process_word_document(input_path, output_path)
        if result:
            if modified:
                print(f"  ✅ aaa已替换换行,已保存")
            else:
                print(f"  ⚠️ 无aaa标记,直接复制")
            success += 1
        else:
            print(f"  ❌ 处理失败")
        print()

    print(f"\n✅ 处理完成!成功处理 {success}/{len(docx_files)} 个文件")
    print(f"📂 处理后文档保存在: {PROCESSED_FOLDER}")
    return True


def check_winrar_installed():
    possible_paths = [
        r"C:\Program Files\WinRAR\WinRAR.exe",
        r"C:\Program Files (x86)\WinRAR\WinRAR.exe"
    ]
    for path in possible_paths:
        if os.path.exists(path):
            return path
    return None


def step4_pack_to_rar():
    """第四步:打包RAR/ZIP"""
    print("\n" + "="*60)
    print("第四步:打包压缩文件")
    print("="*60)
    if not os.path.exists(PROCESSED_FOLDER):
        print(f"❌ 错误:最终文件夹不存在 - {PROCESSED_FOLDER}")
        return False
    files = os.listdir(PROCESSED_FOLDER)
    if not files:
        print(f"⚠️ 警告:最终文件夹为空,没有文件可打包")
        return False
    print(f"📁 待打包文件夹: {PROCESSED_FOLDER}")
    print(f"📊 文件数量: {len(files)}")

    winrar_path = check_winrar_installed()
    if winrar_path:
        try:
            print("🔄 使用WinRAR打包...")
            cmd = [
                winrar_path,
                'a',
                '-ep1',
                '-r',
                RAR_PATH,
                f'{PROCESSED_FOLDER}\\*.*'
            ]
            subprocess.run(cmd, capture_output=True, text=True)
            if os.path.exists(RAR_PATH):
                size = os.path.getsize(RAR_PATH) / 1024
                print(f"✅ RAR打包成功!📏 {size:.2f} KB")
                return True
            else:
                print("⚠️ WinRAR打包失败,切换ZIP")
                return create_zip_backup()
        except Exception as e:
            print(f"⚠️ WinRAR异常:{e},切换ZIP")
            return create_zip_backup()
    else:
        print("⚠️ 未检测WinRAR,生成ZIP")
        return create_zip_backup()


def create_zip_backup():
    try:
        print("🔄 创建ZIP压缩包")
        with zipfile.ZipFile(ZIP_PATH, 'w', zipfile.ZIP_DEFLATED) as zipf:
            for root, dirs, files in os.walk(PROCESSED_FOLDER):
                for file in files:
                    fp = os.path.join(root, file)
                    arc = os.path.relpath(fp, PROCESSED_FOLDER)
                    zipf.write(fp, arc)
        if os.path.exists(ZIP_PATH):
            size = os.path.getsize(ZIP_PATH)/1024
            print(f"✅ ZIP打包成功!📏 {size:.2f} KB")
            print("注:如需RAR格式,请安装WinRAR后重新运行")
            return True
        else:
            print("❌ ZIP打包失败")
            return False
    except Exception as e:
        print(f"❌ ZIP出错:{e}")
        return False


def main():
    print("\n" + "="*60)
    print("一分园|育儿知识(中2班)完整工作流")
    print("="*60)
    print(f"基础路径: {BASE_PATH}")
    print(f"班级: {CLASS_NAME}")
    print(f"业务: {EDU_THEME}")
    print("="*60)

    # # 第一步:生成Excel占位符(取消注释启用)
    # if not step1_generate_excel():
    #     print("❌ 第一步失败,程序终止")
    #     return

    # 第二步:生成Word
    if not step2_generate_word_from_excel():
        print("❌ 第二步失败,程序终止")
        return

    # 第三步:处理aaa换行
    if not step3_process_documents():
        print("❌ 第三步失败,程序终止")
        return

    # 第四步打包
    step4_pack_to_rar()

    print("\n" + "="*60)
    print("🎉 全部流程完成!")
    print("="*60)
    print(f"1️⃣ Excel模板:{EXCEL_PATH}")
    print(f"2️⃣ 原始输出Word:{OUTPUT_FOLDER}")
    print(f"3️⃣ 处理完成Word:{PROCESSED_FOLDER}")
    if os.path.exists(RAR_PATH):
        print(f"4️⃣ RAR压缩包:{RAR_PATH}")
    elif os.path.exists(ZIP_PATH):
        print(f"4️⃣ ZIP压缩包:{ZIP_PATH}")
    print("="*60)


if __name__ == "__main__":
    main()

修改内容

修改1:段落前空格

修改2:去掉RAR

修改3 删除过度文件

修改4:文字少了,尝试增加文字数量

虽然改成400字,但有的内容还是很少。

改成450字

还是很少,我决定重新开一个豆包界面,用450字

请根据附件 1 里面的文字的样式,和附件 2 的占位符字母,帮我做 10 份差不多的育儿知识内容(2026 年 9-12 月,2027 年 1-6 月)根据季节和中班幼儿年龄特点编写差不多的内容。content1 大约 450 字,content2 大约 450 字,year 写 2026 或 2026,month 写数字,不要 "月",编写的内容做成表格形式。,T1 = 王 T2 = 张,S = 张三,parent = 妈妈。其中 content1 和 content2 的多段内容用 aaa 连接,

这次字多了一点,有一份还超过底部

我已经用了450字了,但是还是凑不满页面,所以考虑,增加行距。

很好!文字很满了

(四)修改班级、老师、家长姓名

那么把班级、老师、家长名字修改好。再手动消除几段文字。

'

'

再生成一次

python 复制代码
'''
育儿知识(中2班)
1. 生成占位符Excel
2. 根据Excel生成Word文档
3. 处理Word文档(aaa转手动换行符、空格缩进)

豆包、Deepseek、阿夏
20260910
'''


import pandas as pd
from docxtpl import DocxTemplate
from docx import Document
from docx.enum.text import WD_BREAK
from docx.shared import Pt
from docx.oxml.ns import qn
import os
import sys
import subprocess
import zipfile
import shutil

# ========== 全局路径配置(只需修改这里) ==========
BASE_PATH = r'D:\Python最终内容\20260906育儿知识中2'
CLASS_NAME = "中2班"
EDU_THEME = "全部主题"
date = '20260904'


# ==============================================
EXCEL_PATH = os.path.join(BASE_PATH, f"{date}{CLASS_NAME}育儿知识({EDU_THEME}).xlsx")
TEMPLATE_PATH = os.path.join(BASE_PATH, "育儿知识模版.docx")
OUTPUT_FOLDER = os.path.join(BASE_PATH, f"01 ({CLASS_NAME}){EDU_THEME}_输出")
PROCESSED_FOLDER = os.path.join(BASE_PATH, f"01 ({CLASS_NAME}){EDU_THEME}_最终")
# RAR_PATH = os.path.join(BASE_PATH, f"01 ({CLASS_NAME}){EDU_THEME}_最终.rar")
# ZIP_PATH = os.path.join(BASE_PATH, f"01 ({CLASS_NAME}){EDU_THEME}_最终.zip")

if sys.platform == 'win32':
    import io
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')


# def step1_generate_excel():
#     """第一步:生成占位符Excel文件(字段和docx模板占位符一一对应)"""
#     print("\n" + "="*60)
#     print("第一步:生成占位符Excel文件")
#     print("="*60)
#     # 与docx模板{{}}一一对应,去掉大括号作为列名
#     df = pd.DataFrame(columns=[
#         'classroom','title','T1','T2','S','parent',
#         'content1','title2','content2','year','month'
#     ])
#     df.to_excel(EXCEL_PATH, index=False)
#     print(f"✅ Excel文件已生成:{EXCEL_PATH}")
#     print(f"📋 Excel表头:{list(df.columns)}")
#     # input('\n请先在Excel中填入AI生成的育儿内容,然后按回车键继续...')
#     return True


def step2_generate_word_from_excel():
    """第二步:根据Excel生成Word文档"""
    print("\n" + "="*60)
    print("第二步:根据Excel生成Word文档")
    print("="*60)
    os.makedirs(OUTPUT_FOLDER, exist_ok=True)
    generated_files = []

    if not os.path.exists(EXCEL_PATH):
        print(f"❌ 错误:Excel不存在 - {EXCEL_PATH}")
        return False
    if not os.path.exists(TEMPLATE_PATH):
        print(f"❌ 错误:模板文件不存在 - {TEMPLATE_PATH}")
        return False

    schedule = pd.read_excel(EXCEL_PATH)
    # 全部字段转为字符串,nan替换为空
    excel_cols = ['classroom','title','T1','T2','S','parent','content1','title2','content2','year','month']
    for col in excel_cols:
        if col in schedule.columns:
            schedule[col] = schedule[col].astype(str).replace('nan', '')

    # 设置默认值
    if 'classroom' not in schedule.columns:
        schedule['classroom'] = CLASS_NAME
    if 'T1' not in schedule.columns:
        schedule['T1'] = '王'
    if 'T2' not in schedule.columns:
        schedule['T2'] = '张'
    if 'S' not in schedule.columns:
        schedule['S'] = '张三'
    if 'parent' not in schedule.columns:
        schedule['parent'] = '妈妈'
    if 'year' not in schedule.columns:
        schedule['year'] = '2026'
    if 'month' not in schedule.columns:
        schedule['month'] = '9'

    schedule.to_excel(EXCEL_PATH, index=False)
    print(f"✅ 已保存Excel")
    print(f"📊 共有 {len(schedule)} 行数据")

    try:
        Document(TEMPLATE_PATH)
        print("✅ 模板验证通过,开始生成文档...")
    except Exception as e:
        print(f"❌ 模板无效: {e}")
        return False

    for index, row in schedule.iterrows():
        try:
            tpl = DocxTemplate(TEMPLATE_PATH)
            # 渲染上下文,完全匹配docx模板{{占位符}}
            context = {
                "classroom": str(row['classroom']) if pd.notna(row['classroom']) else CLASS_NAME,
                "title": str(row['title']) if pd.notna(row['title']) else '',
                "T1": str(row['T1']) if pd.notna(row['T1']) else '王',
                "T2": str(row['T2']) if pd.notna(row['T2']) else '张',
                "S": str(row['S']) if pd.notna(row['S']) else '张三',
                "parent": str(row['parent']) if pd.notna(row['parent']) else '妈妈',
                "content1": str(row['content1']) if pd.notna(row['content1']) else '',
                "title2": str(row['title2']) if pd.notna(row['title2']) else '',
                "content2": str(row['content2']) if pd.notna(row['content2']) else '',
                "year": str(row['year']) if pd.notna(row['year']) else '2026',
                "month": str(row['month']) if pd.notna(row['month']) else '9',
            }
            tpl.render(context)
            temp_path = os.path.join(OUTPUT_FOLDER, f"temp_{index}.docx")
            tpl.save(temp_path)
            doc = Document(temp_path)

            # 月份自动补0:9→09,1→01,11→11
            month_str = str(row['month']) if pd.notna(row['month']) else str(index+1)
            month_str = month_str.zfill(2)
            year_str = str(row['year']) if pd.notna(row['year']) else '2026'
            title_short = str(row['title'])[:18] if pd.notna(row['title']) else '育儿知识'
            filename = f"{year_str}.{month_str} 育儿知识({title_short}).docx"

            file_full_path = os.path.join(OUTPUT_FOLDER, filename)
            doc.save(file_full_path)

            if os.path.exists(temp_path):
                os.remove(temp_path)
            generated_files.append(file_full_path)
            print(f"✅ 生成文档: {filename}")
        except Exception as e:
            print(f"❌ 生成第{index+1}行文档失败: {str(e)}")
            import traceback
            traceback.print_exc()
            continue


    print(f"\n📊 文档生成完成!共生成 {len(generated_files)} 个文档")
    print(f"📂 输出目录: {OUTPUT_FOLDER}")
    return True


def process_word_document(input_path, output_path):
    """处理单个Word文档:全文段落aaa替换为手动换行符WD_BREAK.LINE"""
    try:
        doc = Document(input_path)
        modified = False

        # 遍历文档所有段落,处理aaa分隔符
        for para in doc.paragraphs:
            if 'aaa' in para.text:
                runs_info = []
                for run in para.runs:
                    runs_info.append({
                        'text': run.text,
                        'bold': run.bold,
                        'italic': run.italic,
                        'underline': run.underline,
                        'font_name': run.font.name,
                        'font_size': run.font.size,
                        'color': run.font.color.rgb if run.font.color else None
                    })
                full_text = para.text
                parts = full_text.split('aaa')
                para.clear()
                for i, part in enumerate(parts):
                    part = part.strip()
                    if part:
                        # 不是第一段,开头增加4个半角空格
                        if i > 0:
                            part = '    ' + part
                        run = para.add_run(part)
                        if runs_info:
                            run.bold = runs_info[0]['bold']
                            run.italic = runs_info[0]['italic']
                            run.underline = runs_info[0]['underline']
                            if runs_info[0]['font_name']:
                                run.font.name = runs_info[0]['font_name']
                                run._element.rPr.rFonts.set(qn('w:eastAsia'), runs_info[0]['font_name'])
                            if runs_info[0]['font_size']:
                                run.font.size = runs_info[0]['font_size']
                            if runs_info[0]['color']:
                                run.font.color.rgb = runs_info[0]['color']
                        # 添加手动换行符,不是最后一段就换行
                        if i < len(parts) - 1:
                            para.add_run().add_break(WD_BREAK.LINE)
                modified = True

        doc.save(output_path)
        if os.path.exists(output_path):
            return True, modified
        else:
            return False, False
    except Exception as e:
        print(f"    错误: {str(e)}")
        import traceback
        traceback.print_exc()
        return False, False


def step3_process_documents():
    """第三步:批量处理Word文档"""
    print("\n" + "="*60)
    print("第三步:处理Word文档(aaa转手动换行符)")
    print("="*60)
    os.makedirs(PROCESSED_FOLDER, exist_ok=True)
    print(f"输入文件夹: {OUTPUT_FOLDER}")
    print(f"输出文件夹: {PROCESSED_FOLDER}")
    print("-" * 60)

    if not os.path.exists(OUTPUT_FOLDER):
        print(f"❌ 错误: 输入文件夹不存在!")
        return False

    docx_files = [f for f in os.listdir(OUTPUT_FOLDER) if f.lower().endswith('.docx')]
    if not docx_files:
        print(f"⚠️ 没有找到docx文件!")
        return False

    print(f"\n✅ 找到 {len(docx_files)} 个docx文件")
    print("-" * 60)
    success = 0
    for i, filename in enumerate(docx_files, 1):
        print(f"[{i}/{len(docx_files)}] {filename}")
        input_path = os.path.join(OUTPUT_FOLDER, filename)
        output_filename = filename
        output_path = os.path.join(PROCESSED_FOLDER, output_filename)
        result, modified = process_word_document(input_path, output_path)
        if result:
            if modified:
                print(f"  ✅ aaa已替换换行,已保存")
            else:
                print(f"  ⚠️ 无aaa标记,直接复制")
            success += 1
        else:
            print(f"  ❌ 处理失败")
        print()

    print(f"\n✅ 处理完成!成功处理 {success}/{len(docx_files)} 个文件")
    print(f"📂 处理后文档保存在: {PROCESSED_FOLDER}")
    return True


def check_winrar_installed():
    possible_paths = [
        r"C:\Program Files\WinRAR\WinRAR.exe",
        r"C:\Program Files (x86)\WinRAR\WinRAR.exe"
    ]
    for path in possible_paths:
        if os.path.exists(path):
            return path
    return None


def step4_pack_to_rar():
    """第四步:打包RAR/ZIP"""
    print("\n" + "="*60)
    print("第四步:打包压缩文件")
    print("="*60)
    if not os.path.exists(PROCESSED_FOLDER):
        print(f"❌ 错误:最终文件夹不存在 - {PROCESSED_FOLDER}")
        return False
    files = os.listdir(PROCESSED_FOLDER)
    if not files:
        print(f"⚠️ 警告:最终文件夹为空,没有文件可打包")
        return False
    print(f"📁 待打包文件夹: {PROCESSED_FOLDER}")
    print(f"📊 文件数量: {len(files)}")

    winrar_path = check_winrar_installed()
    if winrar_path:
        try:
            print("🔄 使用WinRAR打包...")
            cmd = [
                winrar_path,
                'a',
                '-ep1',
                '-r',
                RAR_PATH,
                f'{PROCESSED_FOLDER}\\*.*'
            ]
            subprocess.run(cmd, capture_output=True, text=True)
            if os.path.exists(RAR_PATH):
                size = os.path.getsize(RAR_PATH) / 1024
                print(f"✅ RAR打包成功!📏 {size:.2f} KB")
                return True
            else:
                print("⚠️ WinRAR打包失败,切换ZIP")
                return create_zip_backup()
        except Exception as e:
            print(f"⚠️ WinRAR异常:{e},切换ZIP")
            return create_zip_backup()
    else:
        print("⚠️ 未检测WinRAR,生成ZIP")
        return create_zip_backup()


def create_zip_backup():
    try:
        print("🔄 创建ZIP压缩包")
        with zipfile.ZipFile(ZIP_PATH, 'w', zipfile.ZIP_DEFLATED) as zipf:
            for root, dirs, files in os.walk(PROCESSED_FOLDER):
                for file in files:
                    fp = os.path.join(root, file)
                    arc = os.path.relpath(fp, PROCESSED_FOLDER)
                    zipf.write(fp, arc)
        if os.path.exists(ZIP_PATH):
            size = os.path.getsize(ZIP_PATH)/1024
            print(f"✅ ZIP打包成功!📏 {size:.2f} KB")
            print("注:如需RAR格式,请安装WinRAR后重新运行")
            return True
        else:
            print("❌ ZIP打包失败")
            return False
    except Exception as e:
        print(f"❌ ZIP出错:{e}")
        return False


def main():
    print("\n" + "="*60)
    print("一分园|育儿知识(中2班)完整工作流")
    print("="*60)
    print(f"基础路径: {BASE_PATH}")
    print(f"班级: {CLASS_NAME}")
    print(f"业务: {EDU_THEME}")
    print("="*60)

    # 第一步:生成Excel占位符(取消注释启用)
    # if not step1_generate_excel():
    #     print("❌ 第一步失败,程序终止")
    #     return

    # 第二步:生成Word
    if not step2_generate_word_from_excel():
        print("❌ 第二步失败,程序终止")
        return

    # 第三步:处理aaa换行
    if not step3_process_documents():
        print("❌ 第三步失败,程序终止")
        return

    # 第四步打包
    # step4_pack_to_rar()

    # ==========新增:删除OUTPUT_FOLDER临时输出文件夹 ==========
    try:
        if os.path.exists(OUTPUT_FOLDER):
            shutil.rmtree(OUTPUT_FOLDER)
            print(f"\n🗑️ 已删除临时文件夹:{OUTPUT_FOLDER}")
    except Exception as e:
        print(f"\n⚠️ 删除临时文件夹失败,请手动删除:{OUTPUT_FOLDER},错误信息:{str(e)}")
    # ==========================================================

    print("\n" + "="*60)
    print("🎉 全部流程完成!")
    print("="*60)
    print(f"1️⃣ Excel模板:{EXCEL_PATH}")
    print(f"2️⃣ 原始输出Word:{OUTPUT_FOLDER}")
    print(f"3️⃣ 处理完成Word:{PROCESSED_FOLDER}")
    # if os.path.exists(RAR_PATH):
    #     print(f"4️⃣ RAR压缩包:{RAR_PATH}")
    # elif os.path.exists(ZIP_PATH):
    #     print(f"4️⃣ ZIP压缩包:{ZIP_PATH}")
    print("="*60)

if __name__ == "__main__":
    main()

修改多的文字的数量(excle里面删除)

运行后就是一页的

(五)把docx合并PDF便于打印

1.找以前的代码,复用代码

2.手动修改各类参数

把word保存为PDF(放到另外一个文件夹)

再把单个PDF转为图片JPG,制作园园通上传图片

第三个代码

python 复制代码
'''
育儿知识(中2班)
把育儿知识202609-202706的docx转PDF,多个PDF合并PDF、转为图片
星火讯飞、阿夏
20260910
'''


from docx2pdf import convert
import os
from PyPDF2 import PdfMerger
import fitz  # PyMuPDF
import time

BASE_PATH = r'D:\Python最终内容\20260906育儿知识中2'
CLASS_NAME = "中2班"
EDU_THEME = "全部主题"
date = '20260910'

new_folder = BASE_PATH + fr'\01 ({CLASS_NAME}){EDU_THEME}_最终'
PDF_folder = BASE_PATH + fr'\01 ({CLASS_NAME}){EDU_THEME}_PDF'
JPG_folder = BASE_PATH + fr'\01 ({CLASS_NAME}){EDU_THEME}_JPG'

# 创建文件夹
os.makedirs(PDF_folder, exist_ok=True)
os.makedirs(JPG_folder, exist_ok=True)

# ==========1.docx批量转PDF==========
docx_files = [f for f in os.listdir(new_folder) if f.endswith('.docx') and not f.startswith('~$')]
for docx in docx_files:
    inputFile = os.path.join(new_folder, docx)
    pdf_name = os.path.splitext(docx)[0] + '.pdf'
    outputFile = os.path.join(PDF_folder, pdf_name)
    print(f"正在转换word:{docx}")
    convert(inputFile, outputFile)
    time.sleep(2)
print('----------Word转PDF完成------------')

# ==========2.所有PDF合并为打印总PDF==========
print('----------开始合并PDF------------')
pdf_lst = [f for f in os.listdir(PDF_folder) if f.endswith('.pdf')]
pdf_lst.sort()
file_merger = PdfMerger()
for pdf in pdf_lst:
    pdf_path = os.path.join(PDF_folder, pdf)
    print(f"合并:{pdf_path}")
    file_merger.append(pdf_path)

merged_pdf_path = os.path.join(BASE_PATH, f"{date}{CLASS_NAME}育儿知识{len(docx_files)}份_打印版.pdf")
file_merger.write(merged_pdf_path)
file_merger.close()
print(f"合并完成,输出:{merged_pdf_path}")

# ==========3.PDF文件夹每个PDF转JPG图片【PyMuPDF,无需poppler】==========
print('----------PDF批量转JPG图片------------')
for pdf_file in pdf_lst:
    pdf_full_path = os.path.join(PDF_folder, pdf_file)
    base_name = os.path.splitext(pdf_file)[0]
    print(f"正在转图片:{pdf_file}")
    doc = fitz.open(pdf_full_path)
    for page_idx, page in enumerate(doc, start=1):
        # zoom控制清晰度,zoom=2≈200DPI
        mat = fitz.Matrix(2, 2)
        pix = page.get_pixmap(matrix=mat)
        jpg_filename = f"{base_name}.jpg"
        jpg_save_path = os.path.join(JPG_folder, jpg_filename)
        pix.save(jpg_save_path)
    doc.close()
    time.sleep(0.5)

print("\n✅全部任务完成:")
print(f"👉单份PDF目录:{PDF_folder}")
print(f"👉JPG图片目录:{JPG_folder}")
print(f"👉合并打印PDF:{merged_pdf_path}")

word模版上传

(不过没有什么复用可能,每个班级的育儿知识模版都不同。学期用的模版都不同,都要重新制作占位符字母)

四、分类整理

(一)word转入学期文件夹

(二)PDF 合并打印

明天就去彩打

(三)制作图片(便于上传园园通班级主页)

相关推荐
君顾11 小时前
智慧场馆解决方案小程序系统实战:从架构设计到上线指南
java·开发语言·智慧场馆
zhougl9961 小时前
Dockerfile实战教程
java·开发语言·spring boot
FfHUCisI1 小时前
Golang 网络轮询器 netpoll:把阻塞 IO 变成事件通知
开发语言·网络·golang
XiaoQiao6669991 小时前
C 语言常用头文件及里面核心函数
c语言·开发语言
AC赳赳老秦1 小时前
环保监测公开数据应用:OpenClaw 抓取空气与水质公开监测数据,开展区域环境质量趋势分析
大数据·数据库·人工智能·python·php·deepseek·openclaw
statistican_ABin1 小时前
中国宠物经济发展分析报告——基于R语言的2018-2024年宠物市场多维度分析
开发语言·r语言·宠物
Zhu7582 小时前
部署安全的pg数据库,搭配pgadmin实现web界面管理
前端·数据库·安全
matlab代码2 小时前
基于matlab PCA人脸识别系统【源码63期】
开发语言·matlab
Terra.K2 小时前
后端开发阶段性总结
java·开发语言·后端