Python 進階實戰:深入 Word 核心,挖出那一坨 BLOB (含自省 Debug 技巧, Binary Large Object) ; part = doc.part.rels[rid].target_part ; return part.blob if “ImagePart” in type(part).__name__ else None

加入好友
加入社群
Python 進階實戰:深入 Word 核心,挖出那一坨 BLOB (含自省 Debug 技巧, Binary Large Object) ; part = doc.part.rels[rid].target_part ; return part.blob if "ImagePart" in type(part).__name__ else None - 儲蓄保險王

# Python 進階實戰:深入 Word 核心,挖出那一坨 BLOB (含自省 Debug 技巧)

我們在處理自動化文件時,常會遇到一個需求:**把 Word 裡的圖片通通抓出來**

這看似簡單,但如果你深入 `python-docx` 的底層,會發現這牽涉到對 Office Open XML (OOXML) 結構的理解、二進位資料 (BLOB) 的處理,以及如何優雅地處理錯誤。

本文將以 `extract_image_bytes` 這個函式為例,解析三個 Python 進階技巧:

1.  **OOXML 關係遍歷** (Relationship Traversal)

2.  **BLOB 的概念與命名哲學**

3.  **Python 自省機制** (Introspection) 來優化 Log

## 1. 核心程式碼賞析

這是我們今天要解構的函式:

# %%
def extract_image_bytes(doc: DocxDocument, rid: str):
    """從 doc.part.rels 取得圖片 bytes"""
    try:
        # 1. 透過 Relationship ID (rId) 找到目標 Part
        part = doc.part.rels[rid].target_part
        
        # 2. 判斷它是不是圖片是的話回傳 BLOB (一坨史萊姆)
        # BLOB (Binary Large Object) - 也就是一坨像史萊姆的無定形團塊
        return part.blob if "ImagePart" in type(part).__name__ else None
        
    except (KeyError, AttributeError) as e:
        # 3. 使用自省機制動態取得函式名稱
        func_name = sys._getframe().f_code.co_name
        print(f"  [Warn] At {func_name}: Failed to extract image for rid={rid}\n  Error: {e}")
        return None
Python 進階實戰:深入 Word 核心,挖出那一坨 BLOB (含自省 Debug 技巧, Binary Large Object) ; part = doc.part.rels[rid].target_part ; return part.blob if "ImagePart" in type(part).__name__ else None - 儲蓄保險王

## 2. 深入解析

### A. 什麼是 BLOB?為什麼叫它「史萊姆」?

在程式碼中,我們看到這行回傳:

return part.blob

`blob` 是 **Binary Large Object** 的縮寫,在電腦科學中指「一塊大型的二進位資料」。

這段資料對人類來說是不可讀的亂碼,沒有固定的形狀。

因此,工程師門常戲稱它為 **”The Blob”** —— 就像 1958 年恐怖電影裡的黏液怪物,或 RPG 遊戲裡的**史萊姆**。它就只是一坨 bytes,直到你賦予它副檔名 (如 `.jpg`, `.png`),它才會變成你能理解的圖片。

### A.2. 逐步拆解:如何找到這坨 BLOB?

你可能會好奇 `doc.part.rels[rid].target_part` 這行程式碼這麼長,中間到底發生了什麼事?我們可以把它拆解成四個步驟:

1.  **`doc.part` (Document Part)**:

    `doc` 只是最外層的包裝,`doc.part` 才是真正的 OOXML 文件主體 (Main Document Part)。

2.  **`.rels` (Relationships)**:

    OOXML 是一個「關聯式」的結構。文件主體不會直接包含圖片,而是紀錄一張「藏寶圖」,告訴你「rId1 連接到圖片A」、「rId2 連接到樣式表」。`.rels` 就是這張藏寶圖。

3.  **`[rid]` (Lookup)**:

    我們拿著從 XML 標籤 (`<w:drawing r:id=”rId1″>`) 找到的 ID (`rId1`),去查這張藏寶圖,得到一個「關聯物件 (Relationship Object)」。這是一條線,連接著起點與終點。

4.  **`.target_part` (The Treasure)**:

    這條線的終點 (`target`),就是我們要找的寶藏——圖片本身 (`ImagePart`)。

### B. Pythonic 的一行流寫法 (One-liner)

return part.blob if "ImagePart" in type(part).__name__ else None

這行展示了 Python 簡潔的 **Ternary Operator (三元運算子)**

*   **邏輯**:如果是圖片 -> 給你資料;如果不是 -> 給你 None。

*   **字串檢查**:透過 `type(part).__name__` 我們可以拿到類別名稱字串 (例如 `’ImagePart’`),這比 `isinstance` 有時更適合處理在動態生成類別或不確定 import路徑的情況。

### C. 自省機制:讓程式知道「我是誰」

func_name = sys._getframe().f_code.co_name

這是這段程式碼最精華的 Debug 技巧。通常我們寫 Log 會這樣寫:

`print(“Error in extract_image_bytes: …”)`

但如果以後函式改名了,Log 裡的字串通常會忘記改,造成誤導。

透過 `sys._getframe()` (取得當前 Stack Frame) -> `.f_code` (程式碼物件) -> `.co_name` (名稱),程式可以**動態抓取自己的名稱**

不管你把函式名稱改成 `get_photo` 還是 `fetch_blob`,這行 Log 永遠都是正確的!

## 3. 實戰應用場景

這個函式通常配合 **Xpath** 一起使用。Word 的 XML 結構中,圖片藏在 `<w:drawing>` 標籤裡,裡面會有一個 `r:embed=”rId1″`。

我們的工作流程如下:

1.  用 Xpath 找出所有 `r:embed` 的 ID。

2.  丟進 `extract_image_bytes(doc, “rId1”)`。

3.  函式幫我們去 `.rels` 關係表中查找,抓出那一坨 **BLOB**

4.  最後寫入硬碟,變成真正的圖檔。

## 總結

一段不到 10 行的 Python 程式碼,其實蘊含了對檔案結構的理解 (OOXML)、對資料本質的幽默 (BLOB/史萊姆),以及對程式維護性的堅持 (Introspection)。

下次當你處理二進位資料時,不妨也想像自己正在處理一坨可愛的史萊姆吧!

推薦hahow線上學習python: https://igrape.net/30afN

加入好友
加入社群
Python 進階實戰:深入 Word 核心,挖出那一坨 BLOB (含自省 Debug 技巧, Binary Large Object) ; part = doc.part.rels[rid].target_part ; return part.blob if "ImagePart" in type(part).__name__ else None - 儲蓄保險王

儲蓄保險王

儲蓄險是板主最喜愛的儲蓄工具,最喜愛的投資理財工具則是ETF,最喜愛的省錢工具則是信用卡

You may also like...

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *