You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在无Excel环境的Python中提取XLS文件的文本框与图片

无Excel环境下提取XLS文件中的文本框与图片

先纠正一个关键错误

XLS是二进制OLE复合文档,不是XLSX那种ZIP压缩包,你之前用zipfile直接解压解析的方法完全不对,这就是为什么只能拿到部分文本的原因。

两种可行替代方案

方案一:纯Python解析BIFF格式(无额外软件依赖)

XLS里的绘图对象(文本框、图片)都存在工作表的OLE流中,用olefile可以读取这些流,再结合BIFF8格式规范解析记录:

import olefile
import struct
from io import BytesIO
from PIL import Image
import base64

def extract_xls_elements(xls_path, sheet_name="Sheet1"):
    with olefile.OleFileIO(xls_path) as ole:
        # 定位目标工作表的Drawing流路径
        drawing_stream_path = f"Workbook/Worksheets/{sheet_name}/Drawing"
        if not ole.exists(drawing_stream_path):
            print(f"工作表{sheet_name}无绘图对象")
            return
        
        drawing_data = ole.openstream(drawing_stream_path).read()
        offset = 0
        total_len = len(drawing_data)
        
        while offset < total_len:
            # 读取BIFF记录头:类型(2字节)+长度(2字节)
            rec_type = struct.unpack('<H', drawing_data[offset:offset+2])[0]
            rec_len = struct.unpack('<H', drawing_data[offset+2:offset+4])[0]
            rec_content = drawing_data[offset+4:offset+4+rec_len]
            
            # 处理文本框(对应OBJRECORD,类型0x00EC)
            if rec_type == 0x00EC:
                # 解析OBJRECORD中的文本内容,需参考BIFF8规范提取文本框的Text部分
                try:
                    # 跳过无关字段,定位文本起始位置(示例逻辑,需根据实际文件调整)
                    text_start = rec_content.find(b'\x00\x00') + 2
                    text = rec_content[text_start:].decode('utf-16le').strip('\x00')
                    print(f"文本框内容: {text}")
                except:
                    print("文本框解析失败")
            
            # 处理图片(对应BLIPRECORD,类型0x00F0)
            elif rec_type == 0x00F0:
                # BLIP头占8字节,后面是原始图片数据
                blip_data = rec_content[8:]
                # 判断图片类型:0x06=PNG,0x07=JPG
                blip_type = struct.unpack('<B', rec_content[0:1])[0]
                if blip_type == 0x06:
                    img_format = "PNG"
                elif blip_type == 0x07:
                    img_format = "JPEG"
                else:
                    print(f"未知图片类型: {blip_type}")
                    offset += 4 + rec_len
                    continue
                
                # 转换为base64
                buffered = BytesIO(blip_data)
                img = Image.open(buffered)
                buffered_out = BytesIO()
                img.save(buffered_out, format=img_format)
                img_base64 = base64.b64encode(buffered_out.getvalue()).decode("utf-8")
                print(f"图片base64编码: {img_base64[:50]}...")
            
            offset += 4 + rec_len

# 调用示例
extract_xls_elements("ewf.xls")

注意:这个方案需要熟悉BIFF8格式的记录结构(可查微软官方BIFF文档),文本框的解析逻辑可能需要根据实际文件调整,图片解析相对稳定。

方案二:用LibreOffice无头模式转XLSX后处理(实现简单)

如果服务器允许安装LibreOffice,这是最省心的方法:先把XLS转成XLSX,再用openpyxl处理,逻辑和你之前的win32com代码几乎一致:

  1. 安装LibreOffice,确保soffice命令在环境变量中
  2. 执行转换命令:
soffice --headless --convert-to xlsx ewf.xls
  1. 用openpyxl提取内容:
from openpyxl import load_workbook
import base64
from io import BytesIO

wb = load_workbook("ewf.xlsx")
ws = wb["Sheet1"]

# 提取文本框
for shape in ws.shapes:
    if shape.shape_type == "textBox":
        print(f"文本框[{shape.name}]: {shape.text}")
    # 处理分组形状
    elif shape.shape_type == "group":
        print("\n--- 分组形状内容 ---")
        for sub_shape in shape.groupItems:
            if sub_shape.shape_type == "textBox":
                print(f"子文本框[{sub_shape.name}]: {sub_shape.text}")

# 提取图片
for img in ws._images:
    buffered = BytesIO()
    img.image.save(buffered, format="PNG")
    img_base64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
    print(f"图片[{img.name}]base64: {img_base64[:50]}...")

方案对比

  • 方案一:无需额外软件,但需要深入理解BIFF格式,适合严格无依赖的环境;
  • 方案二:实现简单,对各种形状(包括分组)的支持更完善,适合能安装LibreOffice的场景。

内容的提问来源于stack exchange,提问作者Lee Huat Chong

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 12:18:09