Excelレポートの自動化でファイルを壊さない方法:xlsxをzipとして開き、必要なXMLだけ書き換える

週次のExcelレポートを自動化すると、ライブラリで開いて保存しただけでファイルが壊れることがあります。xlsxをzipとして開き必要なXMLだけ書き換える方法と、壊れていないことの確かめ方を、物流・運輸の会社の実例とPythonの例で解説します。

(2026年10月25日更新)

毎週の Excel レポートを自動化しようとして、Python などのライブラリでファイルを開き、値を書き込んで保存する。ところが保存したファイルを Excel で開くと、修復を求めるメッセージが出る、書式が崩れている、図や集計表が消えている。Excel 自動化で「ファイルが壊れる」のは、よくある失敗です。

frectas は、物流・運輸の会社で週次の債権レポートを自動化したとき、まさにこの問題に当たりました。既存の Excel ライブラリで開いて保存すると、ファイルが壊れたのです。そこで、xlsx を zip として開き、変更が必要な XML だけを書き換え、それ以外の部品は1バイトも変えずに戻す方式を取りました。この記事では、その方式と、壊れていないことの確かめ方を、一般的な技術の説明とあわせて書きます。

この記事の数字は、frectas の案件の記録(顧客への報告など)によるもので、区分を添えています。

導入前の作業と、導入後

項目 導入前 導入後 区分
ファイルを開く 開くだけで長い時間がかかる — 顧客報告記載
作業全体 毎週数時間 シート追加から検算までの全工程が数秒で完了 顧客報告記載(検証中・実ファイルで確認中)
結果の正しさ — 手作業の完成品と全項目が一致 顧客報告記載(検証中・実ファイルで確認中)

「数秒」は仕組みが処理する時間、「毎週数時間」は人が作業していた時間です。測っているものが違うので、削減率には換算していません。数秒の処理の前後には、入力ファイルをそろえる、結果を確かめる、といった人の作業が残るからです。

作る前に、AI が要るかを決める

着手したとき、最初にしたのは業務の理解です。作業の指示書、作業の動画、作業前と作業後のファイル一式を分析し、毎週どこがどう変わっているかを調べました。

その結果、毎週の変更は、入力ファイルの値と、前週からの機械的な延長だけで決まると分かりました。人の判断が入る所がないのです。

結果が入力で決まる作業に、生成 AI の推論は要りません。入れると、次の問題が出ます。

  • 同じ入力でも、結果が毎回少しずつ変わることがある
  • 分からない所を推測で埋め、それが誤りだと気づけない
  • 正しく動いたことを、毎回人が確かめ直す必要がある

そこで、AI の推論を使わない確定的な処理にしました。AI を使うかどうかの判断の基準は「物流・運輸の定型業務を AI 化した記録」に詳しく書いています。

なぜライブラリで開いて保存すると壊れるのか

xlsx は XML を zip にまとめたもの

xlsx の拡張子を .zip に変えて展開すると、中身が見えます。主な部品は次のとおりです。

部品 中身
[Content_Types].xml zip の中のどのファイルが何の部品かの一覧
_rels/.rels、xl/_rels/workbook.xml.rels 部品どうしのつながり
xl/workbook.xml シートの一覧と順番、名前の定義、計算の設定
xl/worksheets/sheet1.xml など シートごとのセルの値と数式
xl/sharedStrings.xml セルの文字列の一覧(セルは番号で参照する)
xl/styles.xml 書式の一覧(セルは番号で参照する)
xl/calcChain.xml 数式を計算する順番
xl/externalLinks/、xl/pivotTables/、xl/drawings/ など 外部参照、ピボット、図やグラフ

ライブラリは「読み込んで、一から書き出す」

多くの Excel ライブラリは、これらの部品を読み込んで自分のデータ構造に変え、保存のときに新しいファイルとして書き出します。値を1つ変えただけでも、ファイル全体が作り直されます。ライブラリが扱えない部品や設定は、書き出すときに落ちたり、形が変わったりします。

一般に、壊れやすいのは次のような所です。

壊れやすい所 起きやすいこと
数式と計算結果 数式は残っても、保存されていた計算結果が消え、Excel 以外の画面で空に見える
共有数式(同じ形の数式をまとめて持つ仕組み) 元になるセルを書き換えると、同じ数式を共有していた他のセルの数式が消える
書式・条件付き書式 書式の番号が振り直され、色や表示形式がずれる
外部参照 他のブックへのリンクが外れる、参照先が変わる
ピボットテーブル キャッシュが落ちて、更新できなくなる
図・グラフ・コメント 消える、位置がずれる
マクロ(xlsm) 保存の形式によって消える

小さな表なら問題が出ないこともあります。長年人の手で育ってきた業務の Excel ほど、こうした部品が多く入っていて、壊れやすくなります。

必要な XML だけを書き換える

考え方は単純です。zip の中の部品を一つずつ取り出し、変える必要がある部品だけを書き換え、残りはそのまま新しい zip に入れます。

考え方を示すための簡単な例です(実案件のコードとは違います)。

import zipfile

def rewrite_xlsx(src: str, dst: str, edits: dict) -> None:
    """edits: {部品の名前: 元の中身を受け取って新しい中身を返す関数}"""
    with zipfile.ZipFile(src) as zin, zipfile.ZipFile(dst, "w") as zout:
        for info in zin.infolist():  # 元の並び順を保つ
            data = zin.read(info.filename)
            if info.filename in edits:
                data = edits[info.filename](data)
            zout.writestr(info, data, compress_type=info.compress_type)

シートの XML の中でも、変えるのは対象のセルだけにします。XML のライブラリで読み込んで書き出すと、名前空間の書き方や空白が変わり、比べるときの差分が増えるため、ここでは文字列として必要な所だけを置き換えています。

import re

def set_number(sheet_xml: bytes, ref: str, value: float) -> bytes:
    """数値のセル ref の値だけを書き換える。書式の番号などの属性には触れない"""
    text = sheet_xml.decode("utf-8")
    m = re.search(rf'<c r="{ref}"([^>]*?)(?<!/)>(.*?)</c>', text, re.S)
    if not m or "<v>" not in m.group(2):
        raise ValueError(f"{ref} に値がない")  # 想定と違うときは止める
    if re.search(r'\st="(?!n")', m.group(1)):
        raise ValueError(f"{ref} は数値のセルではない")  # 文字列などのセルは別の扱い
    inner = re.sub(r"<v>.*?</v>", f"<v>{value}</v>", m.group(2), count=1)
    return (text[: m.start(2)] + inner + text[m.end(2):]).encode("utf-8")

実際の業務では、ほかに次のことを考えます。

  • 文字列のセル: 値は sharedStrings.xml の番号で持っているので、一覧に文字列を足して番号を書く
  • シートの追加: シートの XML を足すだけでなく、workbook.xml のシート一覧、workbook.xml.rels のつながり、[Content_Types].xml の一覧にも書き足す
  • 数式の計算結果: 入力の値を変えると、保存されている計算結果は古くなる。仕組みの側で計算して書き込むか、開いたときに Excel に再計算させる設定にする。数式を足したり消したりした場合は、計算順の calcChain.xml を消して Excel に作り直させるのが、一般に行われるやり方です。消すときは、[Content_Types].xml と workbook.xml.rels からも calcChain.xml の記載を外します

想定と違う形のセルに当たったら、推測で書き換えずに止めるのが大事です。黙って書き換えると、壊れたファイルが毎週できあがります。

壊れていないことを確かめる

方式を変えたら、次の順で確かめます。

1. 変わってよい部品だけが変わったか

処理の前と後のファイルで、部品ごとにハッシュ値を比べます。

import hashlib
import zipfile

def part_hashes(path: str) -> dict:
    with zipfile.ZipFile(path) as z:
        return {n: hashlib.sha256(z.read(n)).hexdigest() for n in z.namelist()}

before, after = part_hashes("input.xlsx"), part_hashes("output.xlsx")
for name in sorted(before.keys() | after.keys()):
    if before.get(name) != after.get(name):
        print("変更あり:", name)

書き換えるつもりの部品以外が「変更あり」に出たら、どこかで余計な変更をしています。変わった部品は、XML を整形してから差分を取ると、どのセルが変わったかを目で追えます。

2. 正解と全部突き合わせる

人が手で作った過去の完成品を正解にして、同じ週の入力から仕組みで作ったファイルと、全シートの全セルを比べます。数式と値の両方を見ます。比べるためにライブラリで読み込むのは問題ありません。読むだけで、保存はしないからです。

from itertools import zip_longest

from openpyxl import load_workbook

def diff_cells(made: str, correct: str, data_only: bool) -> list:
    """data_only=False で数式、True で保存されている計算結果を比べる"""
    a = load_workbook(made, data_only=data_only, read_only=True)
    b = load_workbook(correct, data_only=data_only, read_only=True)
    diffs = []
    for name in b.sheetnames:
        rows_a = a[name].iter_rows(values_only=True)
        rows_b = b[name].iter_rows(values_only=True)
        for r, (ra, rb) in enumerate(zip_longest(rows_a, rows_b, fillvalue=()), 1):
            for c, (va, vb) in enumerate(zip_longest(ra, rb), 1):
                if va != vb:
                    diffs.append((name, r, c, va, vb))
    a.close()  # read_only で開いたブックは閉じる
    b.close()
    return diffs

この案件でも、手作業の完成品と全項目が一致することを確かめています(顧客報告記載)。実ファイルでの確認は続けている段階です。

3. Excel で開く

最後に、実際に Excel で開きます。修復を求めるメッセージが出ないこと、書式・図・ピボットが元のとおりであること、再計算した後の値が正解と同じであることを確かめます。

全部の週を点検すると、過去の参照ずれが見つかることがある

自動化の仕組みができると、過去の全部の週のファイルを機械で点検できるようになります。手作業でシートを複製して数式を直す作りの Excel では、別の週のシートを参照したままの数式が、気づかれずに残ることがあります。人の目では全部を見きれない所も、機械なら全部の数式の参照先を比べられます。自動化の副産物として、既存の資料の点検に役立つことがあります。

こんな Excel 業務に向いています

  • 毎週・毎月、同じ形のレポートを、前回のファイルを複製して作っている
  • 変わるのは入力の値と日付の延長だけで、人の判断はほとんど入らない
  • ファイルが重く、開くだけで時間がかかる
  • 図・ピボット・外部参照など、作り直すと困る部品が入っている
  • 以前にライブラリで自動化を試して、ファイルが壊れたことがある

案件の全体像は事例「物流・運輸の会社の定型業務を、現場に入って一つずつ AI 化」に、こうした1業務単位の自動化は「小さな業務の自動化」にまとめています。部署ごとの業務を順に進めたい場合は「FDE 型の伴走支援」をご覧ください。

毎週の Excel レポートを、ファイルを壊さずに自動化したい方は、お問い合わせからご相談ください。作業の手順と、作業前後のファイルの違い(どこが毎週変わるか)を教えていただければ、AI が要る作業か、決まった処理で済む作業かの見立てをお伝えします。

よくある質問

PythonでExcelを開いて保存すると、ファイルが壊れるのはなぜですか?

多くのライブラリは、xlsxの中身を自分のデータ構造に読み込み、保存のときに一から書き出します。ライブラリが扱えない部品(図・ピボットのキャッシュ・外部参照の一部など)は、書き出すときに落ちたり形が変わったりします。値を1つ変えただけでも、ファイル全体が作り直されるためです。

xlsxの中身はどうなっていますか?

xlsxは、XMLファイルと画像などをまとめたzipファイルです。拡張子を.zipに変えて展開すると、シートごとのXML、書式(styles.xml)、文字列の一覧(sharedStrings.xml)、部品どうしの関係を書いた.relsファイルなどが入っています。

自動化したExcelが壊れていないことは、どう確かめればよいですか?

処理の前後でzipの中の部品ごとにハッシュ値を比べ、変わってよい部品だけが変わったことを確かめます。そのうえで、人が手で作った完成品と、セルの数式と値を全部突き合わせます。最後にExcelで開き、修復を求めるメッセージが出ないことを確かめます。

Excelのレポート作成に生成AIを使うべきですか?

結果が入力ファイルと前回の値だけで決まるレポートなら、AIの推論は使わないほうが安全です。同じ入力でも結果が揺れたり、分からない所を推測で埋めたりすると、誤りに気づきにくくなります。生成AIは、文章の要約や解説の下書きのように、人が読んで直す前提の作業に向いています。

まずはお気軽にご相談ください

30分の無料業務診断では、業務の流れを伺い、システムや AI で置き換えられそうな部分と、費用の大まかな目安をお伝えします(内容によっては、後日のお見積もりになります)。「何から手をつければいいか分からない」段階でも大丈夫です。