slug: excel-maestro name: excel-maestro version: "1.0.0" displayName: Excel大師 summary: 解決大檔案記憶體爆炸、格式丟失、科學計數法、公式不計算四大痛點,按檔案規模分層處理。 license: MIT description: |- Excel大師是面向批量表格處理的能力包。它不只羅列指令碼,更解決四個高頻痛點: 大xlsx一載入就記憶體爆炸、用pandas讀寫後格式公式全丟失、長數字變成科學計數法、 data_only=True拿到公式卻是None。
核心能力: - 檔案規模分層:小檔案(<10MB)用pandas、中檔案(10-100MB)用openpyxl流式、大檔案(>100MB)分塊 - 格式保留矩陣:明確哪些操作會丟格式、哪些能保留,給出"兩條路徑"選擇 - 陷阱速查:data_only陷阱、科學計數法陷阱、CSV編碼陷阱、合併單元格陷阱 - 16個可執行指令碼:合併/拆分/篩選/聚合/校驗/VLOOKUP/轉置/模板填充/條件格式等 - 效能最佳化:read_only/write_only流式、批次寫入、列裁剪、分頁讀取
適用場景: - 月底彙總多個部門Excel報表 - 處理超10萬行的大表導致pandas卡死 - 需要保留原Excel的公式、顏色、圖表 - 身份證號/訂單號變成科學計數法 - 多表VLOOKUP對齊主表
差異化: - 原始版本只給指令碼清單,本版補齊"什麼場景用什麼指令碼+為什麼"的決策路徑 - 新增檔案規模分層策略與格式保留矩陣 - 新增四大陷阱章節與對應規避方案 - 增加錯誤程式碼表與故障排查 - 壓縮重複API說明,按需載入reference
觸發關鍵詞:Excel、xlsx、合併、拆分、VLOOKUP、透視、條件格式、科學計數法、openpyxl、pandas tags: - 自動化 - 表格處理 - 效率工具 tools: - read - exec
處理Excel檔案、表格資料、批次轉換或報表生成時應用本skill。核心信條:先看檔案多大,再選工具;先問要不要保格式,再動筆。
| 痛點 | 典型表現 | 本skill對策 |
|---|---|---|
| 大檔案記憶體爆炸 | 50萬行xlsx一載入OOM | 檔案規模分層 + read_only/write_only流式 |
| 格式丟失 | pandas讀寫後顏色/公式/圖表全沒了 | 格式保留矩陣 + 兩條路徑 |
| 科學計數法 | 身份證號變成1.23E+19 | 列格式強制文本 + 寫入前預處理 |
| 公式不計算 | data_only=True拿到None | 區分"讀公式"vs"讀快取值" + 重算方案 |
| 檔案規模 | 行數估計 | 推薦工具 | 關鍵引數 |
|---|---|---|---|
| 小檔案 | <1萬行 | pandas | pd.read_excel(engine="openpyxl") |
| 中檔案 | 1萬-50萬行 | openpyxl | load_workbook(read_only=True) |
| 大檔案 | >50萬行 | openpyxl流式 + 分塊 | read_only=True + write_only=True + 分頁 |
| 超大檔案 | >100萬行 | 列裁剪 + 分塊 + 落地CSV | 配合pandas chunksize |
from openpyxl import load_workbook
# read_only=True 不把整個檔案載入記憶體
wb = load_workbook("big.xlsx", read_only=True, data_only=True)
ws = wb["Sheet1"]
for row in ws.iter_rows(values_only=True):
# 逐行處理,記憶體恆定
process(row)
wb.close() # read_only 必須顯式關閉
from openpyxl import Workbook
wb = Workbook(write_only=True) # 流式寫,無法修改已寫行
ws = wb.create_sheet("結果")
ws.append(["列A", "列B", "列C"])
for row in data_stream:
ws.append(row)
wb.save("output.xlsx") # 不會OOM
90%的"格式丟失"問題源於選錯了工具。
| 操作需求 | 用pandas | 用openpyxl | 說明 |
|---|---|---|---|
| 純資料讀寫 | ✅ | ✅ | pandas更簡潔 |
| 保留單元格顏色/字型 | ❌ | ✅ | pandas會丟 |
| 保留公式 | ❌ | ✅ | pandas只存值或公式字串 |
| 保留圖表/透視表 | ❌ | ⚠️部分 | openpyxl能保留已有圖表,不能新建複雜圖表 |
| 保留合併單元格 | ❌ | ✅ | pandas會展開 |
| 保留條件格式 | ❌ | ✅ | pandas會丟 |
| 多表合併/分析 | ✅ | ⚠️慢 | pandas DataFrame更適合 |
| 大檔案流式 | ⚠️chunksize | ✅read_only | openpyxl更穩 |
路徑A:純資料處理(不關心格式)
import pandas as pd
df = pd.read_excel("input.xlsx", engine="openpyxl")
# ... 處理 ...
df.to_excel("output.xlsx", index=False, engine="openpyxl")
路徑B:保留原格式改資料(只動目標單元格)
import openpyxl
wb = openpyxl.load_workbook("input.xlsx") # 不加read_only
ws = wb["Sheet1"]
ws["C2"] = new_value # 只改這一格,其餘格式全保留
wb.save("output.xlsx")
# 錯誤:檔案從未被Excel開啟過,公式沒有快取值
wb = openpyxl.load_workbook("file.xlsx", data_only=True)
ws = wb.active
print(ws["A1"].value) # None,因為公式結果從未被Excel計算並儲存
# 正確方案1:用Excel開啟儲存一次(讓Excel寫入快取值)
# 正確方案2:用formulas庫重算
# pip install formulas
import formulas
xl = formulas.ExcelModel().loads("file.xlsx").finish()
sol = xl.calculate()
# 正確方案3:只讀公式字串(不讀值)
wb = openpyxl.load_workbook("file.xlsx", data_only=False)
print(ws["A1"].value) # "=SUM(B1:B10)" 公式字串
# 錯誤:身份證號110101199001011234變成1.10E+17
df = pd.read_excel("input.xlsx")
df["身份證號"] # 已是float,精度丟失
# 正確方案1:讀取時指定dtype
df = pd.read_excel("input.xlsx", dtype={"身份證號": str})
# 正確方案2:openpyxl讀
wb = openpyxl.load_workbook("input.xlsx")
ws = wb.active
for row in ws.iter_rows(values_only=True):
id_card = str(row[0]) # 字串保留
# 正確方案3:寫入前強制文本格式
from openpyxl.styles import numbers
ws["A1"].number_format = numbers.FORMAT_TEXT
ws["A1"] = "110101199001011234"
# 錯誤:中文亂碼或報錯
df = pd.read_csv("input.csv") # 預設UTF-8,但Excel匯出的CSV可能是GBK
# 正確方案1:嘗試多種編碼
for enc in ["utf-8", "gbk", "gb18030", "utf-8-sig"]:
try:
df = pd.read_csv("input.csv", encoding=enc)
break
except UnicodeDecodeError:
continue
# 正確方案2:寫入CSV時加BOM(讓Excel正確識別UTF-8)
df.to_csv("output.csv", index=False, encoding="utf-8-sig")
# 讀取:合併單元格只有左上角有值,其餘為None
ws = wb["Sheet1"]
for row in ws.iter_rows():
for cell in row:
if cell.value is None and cell.coordinate in ws.merged_cells:
# 處於合併區域內,取左上角值
pass
# 寫入:先解除合併再寫
from openpyxl.utils import range_boundaries
for merged_range in list(ws.merged_cells.ranges):
ws.unmerge_cells(str(merged_range))
ws["A1"] = value
| 你想做的事 | 呼叫指令碼 | 典型引數 |
|---|---|---|
| 多Excel/多sheet合成一張表 | merge_sheets.py | --inputs 檔案或目錄 --output out.xlsx |
| sheet匯出CSV | excel_to_csv.py | --input file.xlsx --output file.csv |
| CSV轉Excel | csv_to_excel.py | --input a.csv --output a.xlsx |
| 按條件篩選行 | filter_excel.py | --where "列名=值" 或 "列名>100"、"列名~北京" |
| 按行數/按列拆分 | split_excel.py | --by-rows 5000 或 --by-column 地區 |
| 按列去重 | deduplicate_excel.py | --keys 編號 --keep first |
| 分組聚合 | aggregate_excel.py | --group-by 地區 --agg "銷售額:sum" |
| 校驗必填列/重複鍵/空行 | validate_excel.py | --require-cols 列名 --key-cols 列名 |
| 選擇/重新命名列 | select_columns.py | --columns 列1,列2 --rename "舊:新" |
| 兩表按鍵合併(VLOOKUP) | merge_tables.py | --left a.xlsx --right b.xlsx --on 鍵列 |
| 主表對多表VLOOKUP | vlookup_multi.py | --main 主.xlsx --lookups "表1.xlsx:鍵列" |
| 行列轉置 | transpose_excel.py | --input in.xlsx --output out.xlsx |
| 模板填充{{列名}} | template_fill.py | --template t.xlsx --data d.csv --output out.xlsx |
| 重新命名工作表 | rename_sheets.py | --rename "Sheet1:新名" 或 --prefix "2024_" |
| 條件格式 | format_conditional.py | --column C --rule gt --value 100 --fill red |
| 列設為文本格式 | format_columns_as_text.py | --columns 身份證號,訂單號 |
# 進入skill目錄或把scripts/加入PATH
pip install -r scripts/requirements.txt
python scripts/merge_sheets.py --help
# 整表為list of dict(保表頭)
import openpyxl
wb = openpyxl.load_workbook("input.xlsx", read_only=True, data_only=True)
ws = wb.active
rows = list(ws.iter_rows(values_only=True))
header = rows[0]
data = [dict(zip(header, row)) for row in rows[1:]]
wb.close()
# pandas(適合分析、過濾、合併)
import pandas as pd
df = pd.read_excel("input.xlsx", sheet_name=0, engine="openpyxl")
# 指定區域
df = pd.read_excel("input.xlsx", usecols="A:D", header=0, nrows=100)
# 新建並寫入(openpyxl)
from openpyxl import Workbook
from openpyxl.styles import Font
wb = Workbook()
ws = wb.active
ws.title = "結果"
ws.append(["列A", "列B", "列C"])
for row in data_rows:
ws.append(row)
ws["A1"].font = Font(bold=True)
wb.save("output.xlsx")
# pandas多sheet寫出
with pd.ExcelWriter("output.xlsx", engine="openpyxl") as writer:
df1.to_excel(writer, sheet_name="彙總", index=False)
df2.to_excel(writer, sheet_name="明細", index=False)
# 追加到已有檔案
wb = openpyxl.load_workbook("existing.xlsx")
ws = wb["Sheet1"]
for row in new_rows:
ws.append(row)
wb.save("existing.xlsx")
from pathlib import Path
import openpyxl, json
results = []
errors = []
for file in Path("目錄").glob("*.xlsx"):
try:
wb = openpyxl.load_workbook(file, read_only=True, data_only=True)
ws = wb.active
# 處理...
results.append({"file": file.name, "rows": ws.max_row})
wb.close()
except Exception as e:
errors.append({"file": file.name, "error": str(e)})
continue # 出錯繼續處理其餘檔案
# 彙總報錯列表
if errors:
with open("errors.json", "w", encoding="utf-8") as f:
json.dump(errors, f, ensure_ascii=False, indent=2)
批次輸出命名規則建議:原名_out.xlsx 或統一彙總到一個檔案。
| 場景 | 慢的原因 | 最佳化方案 |
|---|---|---|
| 逐單元格寫入 | 每次write觸發渲染 | 用ws.append(row)批次行寫入 |
| 大檔案讀取OOM | 整檔案載入 | read_only=True流式 |
| 大檔案寫出OOM | 整工作簿在記憶體 | write_only=True流式 |
| 只需部分列 | 讀全部列 | usecols="A:C"列裁剪 |
| 百萬行分析 | 全量載入 | pd.read_excel(chunksize=10000)分塊 |
| 多檔案合併 | 序列讀 | 並行讀(concurrent.futures) |
| 公式重算慢 | 全表重算 | 用formulas庫按需算 |
Path(file).exists()檢查檔案存在write_only=True或分塊openpyxl.utils.exceptions.InvalidFileException、KeyError(工作表名)並返回可讀錯誤| 錯誤 | 原因 | 解決 |
|---|---|---|
InvalidFileException |
檔案不是有效xlsx/xls | 檢查檔案是否損壞、是否實為.csv改字尾 |
KeyError: 'Sheet1' |
工作表名不存在 | 用wb.sheetnames檢視實際表名 |
PermissionError |
檔案被Excel佔用 | 關閉Excel再處理 |
MemoryError |
檔案太大 | 切換read_only流式 |
UnicodeDecodeError |
CSV編碼不對 | 嘗試gbk/gb18030/utf-8-sig |
ValueError: No column |
列名寫錯或有多餘空格 | df.columns = df.columns.str.strip() |
pip install openpyxl pandas xlrd formulas
Q:50萬行Excel一讀就OOM怎麼辦?
A:用load_workbook(read_only=True, data_only=True)流式讀取,配合iter_rows(values_only=True)逐行處理,記憶體恆定。
Q:用pandas讀寫後Excel顏色和公式都沒了? A:pandas只處理資料不處理格式。需要保格式就用openpyxl載入原檔案,只改目標單元格再save(見"路徑B")。
Q:身份證號變成科學計數法怎麼救?
A:讀取時dtype={"身份證號": str},或openpyxl讀後str(cell.value)。寫入前設number_format = FORMAT_TEXT。
Q:data_only=True讀公式單元格是None? A:檔案從未被Excel開啟儲存過,沒有快取值。要麼用Excel開啟存一次,要麼用formulas庫重算,要麼data_only=False讀公式字串。
Q:多個Excel檔案需要合併到一個sheet?
A:用merge_sheets.py --inputs 目錄 --output out.xlsx,或pandas的pd.concat([pd.read_excel(f) for f in files])。
Q:CSV用Excel開啟中文亂碼?
A:寫入時encoding="utf-8-sig"加BOM,Excel就能正確識別UTF-8。
| 症狀 | 可能原因 | 解決 |
|---|---|---|
| 開啟檔案報InvalidFile | 檔案損壞或字尾不符 | 用Excel開啟驗證,或另存為xlsx |
| sheet名找不到 | 有隱藏空格 | wb.sheetnames檢視,strip空格 |
| 寫入後打不開 | write_only模式未append任何行 | 確保至少append一行再save |
| 數值精度丟失 | 用了float存大數 | 改用str或Decimal |
| 條件格式不生效 | 規則寫錯或範圍不對 | 先用Excel手動驗證規則 |
| 公式顯示為文本 | 單元格格式是文本 | 設number_format = 'General'再寫公式 |
7w4.net提供免費和付費技能下載。
| 依賴項 | 型別 | 是否必需 | 獲取方式 |
|---|---|---|---|
| openpyxl | Python庫 | 必需 | pip install openpyxl |
| pandas | Python庫 | 必需 | pip install pandas |
| xlrd | Python庫 | 可選(讀.xls) | pip install xlrd |
| formulas | Python庫 | 可選(公式重算) | pip install formulas |
| LLM API | API | 必需 | 由Agent內建LLM提供 |
這個技能質量中等偏上,四大痛點解決思路實用,程式碼示例豐富,對批量表格處理有參考價值。主要問題是文件裡提到的指令碼工具實際上沒有提供,導致可用性大打折扣。部分內容表述不清、存在錯誤。需要有一定程式設計基礎才能使用,新手友好度一般。