Python解析Excel圖表Chart的信息實戰(zhàn)指南
摘要
在數據分析與報表自動化場景中,Excel 圖表往往承載著關鍵業(yè)務信息,但常規(guī)庫對圖表結構與樣式的解析能力有限。本文基于 OpenXML 規(guī)范,通過將 .xlsx 文件視為 ZIP 壓縮包,直接解析 xl/charts/chart*.xml,實現(xiàn)了對 Excel 圖表元數據的精準提取。使用 Python 的 urllib、zipfile 與 xml.etree.ElementTree,完整獲取了圖表標題、系列名稱、X/Y 軸數據,以及標題、坐標軸和數據系列的字體與字號信息。實踐結果表明,該方法無需依賴 Excel 環(huán)境,適用于線上 Excel 文件解析、圖表規(guī)范校驗及報表自動化處理,為 Excel 圖表的深度解析與二次利用提供了一種高效可行的技術方案。
一、背景介紹
在實際項目中,我們經常會遇到這樣的需求:
線上 Excel 文件(HTTP 地址)
不關心單元格數據,而是需要:
- 圖表標題
- 系列名稱
- X / Y 軸數據
- 圖表、坐標軸、系列的字體和字號
然而,openpyxl 等庫并不能完整解析 Excel 圖表的樣式和結構。
事實上,.xlsx 本質上是一個 ZIP 壓縮包,圖表信息存儲在:
xl/charts/chart*.xml
只要我們直接解析這個 XML,就能拿到幾乎全部圖表元數據。
二、整體思路
技術路線
1.通過 urllib 下載 Excel 文件
2.使用 ZipFile 讀取 xlsx 內部結構
3.定位 xl/charts/chart1.xml
4.使用 xml.etree.ElementTree 解析圖表 XML
5.按 OpenXML 規(guī)范解析:
- 標題(title)
- 系列(ser)
- 分類軸(catAx)
- 數值軸(valAx)
- 字體、字號
- X / Y 軸數據
三、核心代碼實現(xiàn)
完整函數代碼
import xml.etree.ElementTree as ET
from zipfile import ZipFile
import io
import urllib.request
def get_chat_info(direct_link):
result = {}
res = {}
try:
# 下載 Excel 文件
file = urllib.request.urlopen(direct_link).read()
archive = ZipFile(io.BytesIO(file))
try:
# 讀取圖表 XML
data = archive.read('xl/charts/chart1.xml')
res['code'] = 200
res['msg'] = "獲取圖表信息成功"
tree = ET.parse(io.BytesIO(data))
root = tree.getroot()
# 命名空間
ns = {
'c': 'http://schemas.openxmlformats.org/drawingml/2006/chart',
'a': 'http://schemas.openxmlformats.org/drawingml/2006/main'
}
# ================== 圖表標題 ==================
title_element = root.find('.//c:title/c:tx/c:rich', ns)
if title_element is not None:
title_text = ""
for t in title_element.iter('{http://schemas.openxmlformats.org/drawingml/2006/main}t'):
title_text += t.text
result['title'] = title_text
title_ax_element = root.find('.//c:chart/c:title/c:tx', ns)
if title_ax_element is not None:
tx_pr = title_ax_element.find('.//a:defRPr', ns)
if tx_pr is not None:
latin = tx_pr.find('.//a:latin', ns)
result['title_font'] = latin.get('typeface') if latin is not None else "no"
result['title_size'] = tx_pr.get('sz') or "no"
# ================== 系列名稱 ==================
ser_elements = root.findall('.//c:chart/c:plotArea/*/c:ser', ns)
series_name = ""
for ser in ser_elements:
v = ser.find('.//c:v', ns)
if v is not None:
series_name = v.text
result['series_name'] = series_name
# ================== X / Y 數據 ==================
x_values, y_values = [], []
for num_ref in root.findall('.//c:numRef', ns):
for v in num_ref.findall('.//c:v', ns):
y_values.append(v.text)
for pt in root.findall('.//c:cat/c:strRef/c:strCache/c:pt', ns):
v = pt.find('.//c:v', ns)
if v is not None:
x_values.append(v.text)
result['x_values'] = x_values
result['y_values'] = y_values
# ================== 數值軸 ==================
val_ax = root.find('.//c:valAx', ns)
if val_ax is not None:
tx_pr = val_ax.find('.//c:txPr/a:p/a:pPr/a:defRPr', ns)
if tx_pr is not None:
latin = tx_pr.find('.//a:latin', ns)
result['valAx_font'] = latin.get('typeface') if latin is not None else "no"
result['valAx_size'] = tx_pr.get('sz') or "no"
# ================== 分類軸 ==================
cat_ax = root.find('.//c:catAx', ns)
if cat_ax is not None:
tx_pr = cat_ax.find('.//c:txPr/a:p/a:pPr/a:defRPr', ns)
if tx_pr is not None:
latin = tx_pr.find('.//a:latin', ns)
result['catAx_font'] = latin.get('typeface') if latin is not None else "no"
result['catAx_size'] = tx_pr.get('sz') or "no"
# ================== 系列字體 ==================
ser = root.find('.//c:chart/c:plotArea/*/c:ser', ns)
if ser is not None:
tx_pr = ser.find('.//a:defRPr', ns)
if tx_pr is not None:
latin = tx_pr.find('.//a:latin', ns)
result['ser_font'] = latin.get('typeface') if latin is not None else "no"
result['ser_size'] = tx_pr.get('sz') or "no"
res['data'] = result
except:
res['code'] = 404
res['msg'] = "未找到圖表信息"
except:
res['code'] = 500
res['msg'] = "未獲取excel信息"
return res
測試示例
aa = get_chat_info("http://192.168.31.161:8080/555.xlsx")
print(aa)
四、運行結果示例
{
"code": 200,
"msg": "獲取圖表信息成功",
"data": {
"title": "各季度采購合理性折線圖",
"title_font": "宋體",
"title_size": "1200",
"series_name": "采購合理性",
"x_values": [
"2018-1", "2018-2", "2018-3", "2018-4",
"Jan-19", "2019-2", "2019-3", "2019-4",
"2020-1", "2020-2", "2020-3", "2020-4",
"2021-1", "2021-2", "2021-3", "2021-4",
"2022-1", "2022-2", "2022-3", "2022-4"
],
"y_values": [
"0.99", "0.92", "0.91", "0.37", "0.85",
"0.97", "0.8", "0.88", "0.67", "0.91",
"0.76", "0.75", "0.99", "0.95", "0.89",
"0.83", "0.44", "0.75", "0.94", "0.41"
],
"valAx_font": "宋體",
"valAx_size": "1000",
"catAx_font": "宋體",
"catAx_size": "1000",
"ser_font": "宋體",
"ser_size": "1000"
}
}
五、關鍵知識點總結
.xlsx 是 ZIP 文件
圖表數據在 xl/charts/chart*.xml
Excel 圖表完全遵循 OpenXML 規(guī)范
字體大小單位為 1/100 磅(pt)
- 1000 = 10pt
- 1200 = 12pt
六、適用場景
- 自動化審計 Excel 報表
- 圖表規(guī)范校驗(字體 / 標題 / 數據完整性)
- Excel → 圖表數據 → Web 可視化
- 報表 AI / LLM 解析前的數據結構化
延伸:Python使用openpyxl從URL讀取Excel并獲取單元格樣式
到此這篇關于Python解析Excel圖表Chart的信息實戰(zhàn)指南的文章就介紹到這了,更多相關Python解析Excel圖表內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Python成功解決讀文件出現(xiàn):IOError:?[Errno?0]?Error的錯誤
在Python編程中,處理文件是常見的任務之一,但偶爾也會遇到各種錯誤,包括IOError,盡管Python?3.x中IOError已被OSError和FileNotFoundError等更具體的異常所取代,由于[Errno?0]不直接指向具體的錯誤類型,我們將討論一系列可能導致IOError的常見情況,需要的朋友可以參考下2024-07-07
flask中使用SQLAlchemy進行輔助開發(fā)的代碼
在Web.py, Django, Flask, Tornado里,自帶的ORM功能比較缺乏,推薦大家使用SQLAlchemy來輔助開發(fā)2013-02-02

