テーマ知識の自動生成:Pythonによる週間計画作成ツール

テーマ知識素材を活用した次学期の19週間分のテーマ知識Word作成

背景要件

新学期が始まり、週間計画シリーズを継続し、既存の基盤上でさらなるコード最適化を行います。

準備素材

すべて「02 テーマ知識」フォルダ内のコンテンツを使用します。

第1段階:既存ファイル名の1-9週を01-09週に変更

既存のテーマ知識資料(テーマ知識と情報窓の内容を含む)

ファイル名の週数を2桁に統一します。 ファイル名形式が統一されていないものがあり、週の後にスペースがあったり、窓の後にテーマ名が続いたりしていました。すべて「第X週 テーマ説明」という形式に統一します。

A:まず形式を統一

B:次に1-9週の数字を2桁に補完

コード例:ファイル名の長さを統計

例:「第9週 テーマ知識.doc」は合計12文字、すべての12文字のファイル名に0を追加。もし「第10週 テーマ知識.doc」が13文字の場合は0を追加しない。

import os
import time

path = r"D:\test\02办公类\91周计划4份_2024年中4班\02 主题知识\01doc"
fileList = os.listdir(path)

print(fileList)

for file in fileList:
    # 形式が統一されていない場合、すべての週数を抽出
    split_str = file.split('周')
    newname1 = split_str[0]  # _の第0部分=番号
    print(newname1)
    newname = newname1 + '周 主题知识.doc'
    oldname_path = os.path.join(path, file)
    # ファイルの新しいパス
    newname_path = os.path.join(path, newname)
    # 新旧入れ替え
    os.rename(oldname_path, newname_path)

# 遅延
time.sleep(2)

fileList = os.listdir(path)

# このテーマ説明情報窓とテーマ説明が一緒のもの、第X週後に「テーマ説明」を追加
for file in fileList:
    if len(file) == 12:    # 第9周 主题说明.doc  12は1桁の週数
        print(file)
        split_str = file.split('第')
        newname1 = split_str[0]  # _の第0部分=番号
        print(newname1)
        newname2 = split_str[1]  # _の第0部分=番号
        print(newname2)
        newname = newname1 + '第0' + newname2
        oldname_path = os.path.join(path, file)
        # ファイルの新しいパス
        newname_path = os.path.join(path, newname)
        # 新旧入れ替え
        os.rename(oldname_path, newname_path)

    if len(file) == 13:     # 第10周 主题说明.doc  13は2桁の週数
        pass

第2段階:既存ファイル形式をdocからdocxに変換

コード例:docフォルダ内の19個のdocファイルをdocxフォルダ内の19個のdocxファイルに変換

以前のコードでは絶対パスの二重スラッシュを使用し、docファイルを手動でdocxフォルダにコピーする必要がありました。現在は相対パスを使用し、直接docx内に保存します。

import os
from win32com import client as wc
import time

# ディレクトリの形式は必ず二重スラッシュで記述
path = r"D:\test\02办公类\91周计划4份_2024年中4班\02 主题知识"
oldpath = path + r'\01doc'  # 絶対パスを使用(変更可能)元のdocファイルのパス
newpath = path + r'\02docx'  # 絶対パスを使用(変更可能)docxファイルのパス

# doc内の19週間分のdoc計画ファイルのパスをすべて抽出
files = []
for file in os.listdir(oldpath):
    # .docで終わるファイルかつ~$で始まらないファイルを探す(~$は一時ファイルを除外するため)
    if file.endswith('.doc') and not file.startswith('~$'):
        files.append(oldpath + '\\' + file)
        print(files)

# docファイル内のdocファイルを開き、docxファイル内のdocxファイルとして保存
for file in files:
    word = wc.Dispatch("Word.Application")
    print("処理済みファイル:" + file)
    # ファイルを開く
    doc = word.Documents.Open(file)
    # docxフォルダに.docx形式で保存

    # ここでファイル名の長さに基づいて数字を決定
    new = newpath + '\\' + file[-13:] + 'x'
    print(new)
    doc.SaveAs("{}".format(new), 12)  # 12はdocx形式を表す
    doc.Close()

第3段階:docx内の改行を削除

各docxファイルには空行や改行が含まれている場合があります。これらを削除します。

コード例

from docx import Document
from openpyxl import load_workbook
import glob
import os

path = r"D:\test\02办公类\91周计划4份_2024年中4班\02 主题知识"
for file in glob.glob(path + r'\02docx\*.docx'):   # 以前の情報窓参照資料をすべて読み込む
    doc = Document(file)
    for paragraph in doc.paragraphs:  # ドキュメントの段落を読み込む
        if len(paragraph.text) == 0:
            p = paragraph._element
            p.getparent().remove(p)
            p._p = p._element = None

    doc.save(path + r'\03去掉回车' + "\\" + file[-14:])

第4段階:「テーマ知識」のExcel情報を整理し、中4班下学期「テーマ知識」.xlsxに書き込む

コード例

from docx import Document
from openpyxl import load_workbook
import glob
import re

# テンプレートExcelをプログラムに読み込む:
path = r"D:\test\02办公类\91周计划4份_2024年中4班\02 主题知识"
workbook = load_workbook(path + r'\10 改周次过渡模板_主题知识.xlsx')
sheet = workbook.active

number = 0

# 太字の4つの見出しがある行数を抽出する
for file in glob.glob(path + r'\03去掉回车\*.docx'):
    print(file)

    doc = Document(file)

    # 各ドキュメントの行数を取得
    d = len(doc.paragraphs)

    for i in range(len(doc.paragraphs)):
        if '主题说明:' in doc.paragraphs[i].text:
            h1 = i            # 主题说明が何行目にあるか
            print('主题说明', h1)
    for i in range(len(doc.paragraphs)):
        if '主题目标:' in doc.paragraphs[i].text:
            h2 = i            # 主题目标が何行目にあるか
    for i in range(len(doc.paragraphs)):
        if '家园共育:' in doc.paragraphs[i].text:
            h3 = i            # 家园共育が何行目にあるか

            # # #家园共育の終了値は総行数と等しい
    h4 = d

    z1 = []    # 主题名称:
    # 「主题名称」がある行を検索
    for i in range(len(doc.paragraphs)):
        if '主题名称:' in doc.paragraphs[i].text:
            a1 = doc.paragraphs[i].text
            z1.append(a1[5:])
            # 同じ行で、5から後の漢字を抽出
    content1 = '\n'.join(z1)      # 結合して改行を追加

    z2 = []    # 主题说明:
    # 「主题说明」を抽出
    for paragraph2 in doc.paragraphs[h1+1:h2]:
        t2 = paragraph2.text
        z2.append(t2)
    print(z2)
    content2 = '\n'.join(z2)      # 結合して改行を追加

    z3 = []    # 主题目标:
    # 「主题目标」を抽出
    for paragraph3 in doc.paragraphs[h2+1:h3]:
        t3 = paragraph3.text
        z3.append(t3)
    print(z3)
    content3 = '\n'.join(z3)      # 結合して改行を追加

    z4 = []    # 家园共育:
    # 「家园共育」を抽出
    for paragraph4 in doc.paragraphs[h3+1:]:
        t4 = paragraph4.text
        z4.append(t4)
    print(z4)
    content4 = '\n'.join(z4)      # 結合して改行を追加

    number += 1
    # sheet.append([number, content1, content2, content3, content4])  # numberは番号、contentはテーマ知識の中身の内容

    sheet.cell(row=number+1, column=1).value = number
    sheet.cell(row=number+1, column=2).value = content1
    sheet.cell(row=number+1, column=3).value = content2
    sheet.cell(row=number+1, column=4).value = content3
    sheet.cell(row=number+1, column=5).value = content4

workbook.save(path + r'\11 中4班下学期_主题知识.xlsx')
workbook.close()

print('--XLSXを開き、空白を削除し、1、を1.に置換--')
# Excelファイルを開く
workbook = load_workbook(path + r'\11 中4班下学期_主题知识.xlsx')
# 最初のワークシートを取得
worksheet = workbook.active

# 各セルを反復処理
for row in worksheet.iter_rows():
    for cell in row:
        if cell.value and isinstance(cell.value, str):
            # セル内のテキストの書式をクリア
            cell.value = cell.value.strip()

        # セル内のテキストにスペースがあるかどうかを判断
        if ' ' in str(cell.value):
            # スペースを無スペースに置換
            cell.value = str(cell.value).replace(' ', '')

        if ' ' in str(cell.value):
            # スペースを無スペースに置換
            cell.value = str(cell.value).replace(' ', '')

        # テキストを置換
        for s in range(1, 10):
            if cell.value and isinstance(cell.value, str):
                cell.value = cell.value.replace("{}、".format(s), "{}.".format(s))

# 変更後のExcelファイルを保存
workbook.save(path + r'\11 中4班下学期_主题知识.xlsx')

# Excelファイルを閉じる
workbook.close()

第5段階:Wordテンプレートを読み込み、EXCEL-テーマ知識の内容を合成して19のテーマ知識Docxを作成

コード例

from docxtpl import DocxTemplate
import pandas as pd
import os
import xlwt
import xlrd
import os
import random
from win32com.client import constants, gencache
from win32com.client.gencache import EnsureDispatch
from win32com.client import constants
import os, time
import docx
from docx import Document
from docx.shared import Pt
from docx.shared import RGBColor
from docx.enum.text import WD_PARAGRAPH_ALIGNMENT

path = r"D:\test\02办公类\91周计划4份_2024年中4班\02 主题知识"
print(path)

file_path = path + r'\04合成新主题知识'
print(file_path)

# 二、遍历excel,逐个生成word(小标签.docx是前面的模板)
try:
    os.mkdir(file_path)
except:
    pass

list = pd.read_excel(path + '\\11 中4班下学期_主题知识.xlsx')

title = list["title"].str.rstrip()
name = list["name"]
sm = list["sm"].str.rstrip()
mb = list["mb"].str.rstrip()
gy = list["gy"].str.rstrip()
classroom = list["classroom"].str.rstrip()
time = list["time"].str.rstrip()

# 遍历excel行,逐个生成
numnum = list.shape[0]
for i in range(numnum):
    context = {
        "name": name[i],
        "title": title[i],
        "sm": sm[i],
        "mb": mb[i],
        "gy": gy[i],
        "classroom": classroom[i],
        "time": time[i],
    }
    tpl = DocxTemplate(path + '\\12 主题知识_竖版双.docx')
    tpl.render(context)
    tpl.save(file_path + r"\\第{}周 {}班 主题知识({}).docx".format('%02d' % name[i], classroom[i], time[i]))

第6段階:テーマ知識をPNG形式に変換し、「クラスホームページ」へのアップロードを容易にする

コード例

from win32com.client import Dispatch
import os
import re
import fitz
wdFormatPDF = 17  # 変換タイプ
zoom_x = 2  # サイズ、大きいほど画像が鮮明になる
zoom_y = 2  # サイズ、大きいほど画像が鮮明になる、長さは一致させる
rotation_angle = 0  # 回転角度、0は回転しない

# docxファイルをコピー
import os
import shutil

def copy_docx_files(source_dir, dest_dir):
    for filename in os.listdir(source_dir):
        source_path = os.path.join(source_dir, filename)
        dest_path = os.path.join(dest_dir, filename)
        
        if os.path.isfile(source_path) and filename.endswith(".docx"):
            shutil.copy(source_path, dest_path)
        
        if os.path.isdir(source_path):
            copy_docx_files(source_path, dest_dir)

# 元のフォルダと先のフォルダを指定
old_path = r'D:\test\02办公类\91周计划4份_2024年中4班\02 主题知识\04合成新主题知识'
new_path = r'D:\test\02办公类\91周计划4份_2024年中4班\02 主题知识\05jpg上传'

# コピー関数を呼び出し
copy_docx_files(old_path, new_path)

def doc2pdf2png(input_file):
    for root, dirs, files in os.walk(input_file):
        for file in files:
            if re.search('\.(docx|doc)$', file):
                filename = os.path.abspath(root + "\\" + file)
                print('filename', filename)
                word = Dispatch('Word.Application')
                doc = word.Documents.Open(filename)
                doc.SaveAs(filename.replace(".docx", ".pdf"), FileFormat=wdFormatPDF)
                doc.Close()
        word.Quit()

    for root, dirs, files in os.walk(input_file):
        for file in files:
            if re.search('\.pdf$', file):
                filename = os.path.abspath(root + "\\" + file)
                print('filename', filename)
                # PDFファイルを開く
                pdf = fitz.open(filename)
                # PDFをページごとに読み込む
                for pg in range(0, pdf.pageCount):
                    page = pdf[pg]
                    # 拡大率と回転係数を設定
                    trans = fitz.Matrix(zoom_x, zoom_y).preRotate(rotation_angle)
                    pm = page.getPixmap(matrix=trans, alpha=False)
                    # 画像の書き込みを開始
                    pm.writePNG(filename.replace('.pdf', '') + str(pg+1) + ".png")
                pdf.close()

doc2pdf2png(new_path)

# 生成されたPDFファイルと元のdocxファイルを削除
for parent, dirnames, filenames in os.walk(new_path):
    for fn in filenames:
        if fn.lower().endswith('.pdf'):
            os.remove(os.path.join(parent, fn))
        if fn.lower().endswith('.docx'):
            os.remove(os.path.join(parent, fn))
           
# 生成されたPNGファイルの2-8ページ目を削除(Wordは1ページ目のみが必要)
for parent, dirnames, filenames in os.walk(new_path):
    for fn in filenames:
        for k in range(2, 9):
            if fn.lower().endswith(f'{k}.png'):
                os.remove(os.path.join(parent, fn))

考察

同一ページ上の情報窓とテーマ名の内容をそれぞれ抽出することに成功しました。情報窓とテーマ知識の両方の読み取り(読み取り範囲が異なる)を完了しました。

  1. 今学期の壁面情報窓とテーマ説明は1ページにあります。両方を統合したバージョンも作成する必要があります。

  2. 毎回使用するWordの元素材の形式、内容、構造が異なるため、コードを6つに分け、それぞれのパス、内容選択範囲などを個別に調整するのが最適です。これは非常に細かい作業です。

タグ: Python ドキュメント自動生成 Office自動化 テキスト処理 画像変換

5月25日 17:01 投稿