使用Python解析Excel中的嵌入图片
✏️

使用Python解析Excel中的嵌入图片

Tags
Excel
Embed picture
Python
Published
August 29, 2024
Author
Simon Wong

介绍

最近在使用Python解析Excel表格,表格中有一列数据是图片,需要提取出图片并上传到对象存储服务器中,我使用了openpyxl库来解析Excel,openpyxl中有一个专门的变量可以读取图片信息,然后通过图片的坐标的信息可以对应到单元格中,然后将图片上传到对象存储服务中,并将URL映射到对应的单元格中,就完成了我的目标。就在我以为大功告成之时,我收到了一个使用WPS编辑的Excel文档,里面的图片居然是嵌入在单元格中,单元格中解析后的数据只是一个Excel公式,没有任何图片信息。通过一番搜索,找到了一个巧妙的方法来解析这类嵌入单元格的图片的方法。

原理

  • xlsx本质上是一个zip文件,里面包含有xml文件和媒体文件,通过解压文件可以拿到图片和xml文件
  • 读取excel单元格时可以从公式中获取到嵌入图片的ID
  • 通过解析xml文件获取图片和ID的映射关系
 

实现

import zipfile import xml.etree.ElementTree as ET def extract_embed_images(path): """ 提取Excel表中的嵌入图片并上传 :param fp: 文件指针 :return: 图片URL字典 """ image_urls = {} embed_map = {} id_target_map = {} with zipfile.ZipFile(path, 'r') as zfile: with zfile.open("xl/cellimages.xml") as file: xml_content = file.read() with zfile.open("xl/_rels/cellimages.xml.rels") as file: relxml_content = file.read() root = ET.fromstring(xml_content) namespaces = { 'xdr': 'http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing', 'a': 'http://schemas.openxmlformats.org/drawingml/2006/main' } for pic in root.findall('.//xdr:pic', namespaces=namespaces): name = pic.find('.//xdr:cNvPr', namespaces=namespaces).attrib['name'] embed = pic.find('.//a:blip', namespaces=namespaces).attrib['{http://schemas.openxmlformats.org/officeDocument/2006/relationships}embed'] embed_map[name] = embed root1 = ET.fromstring(relxml_content) namespaces1 = {'r': 'http://schemas.openxmlformats.org/package/2006/relationships'} for child in root1.findall('.//r:Relationship', namespaces=namespaces1): id_target_map[child.attrib['Id']] = child.attrib.get('Target') for name, embed in embed_map.items(): if embed in id_target_map: target = id_target_map[embed] with zfile.open("xl/" + target) as file: image_urls[name] = upload_file(file) return image_urls def upload_file(file): """ 上传文件到文件服务器 """ pass
  • 通过函数extract_embed_images 建立图片ID与图片的映射关系
  • 在解析单元格时如果遇到嵌入图片,则通过查找映射关系,得到该单元格里的图片数据,我这里是将图片上传到文件服务器,你可以按照自己的需求将图片存储在对应的地方,方便后续读取
解析Excel单元格嵌入图片的逻辑如下
import re import openpyxl MAX_COL = 100 path = "your/excel/file/path" image_urls = extract_embed_images(path) def extract_image_id(formula): """ 从公式字符串中提取 image_id :param formula: 公式字符串 :return: 提取的 image_id """ match = re.search(r'=_xlfn\.DISPIMG\("([^"]+)"', formula) if match: return match.group(1) return None workbook = openpyxl(path) sheet = workbook.active for row in sheet.iter_rows(values_only=False): for cell in row[:MAX_COL]: if cell.data_type == 'f' and cell.value.startswith("=_xlfn.DISPIMG"): image_id = extract_image_id(cell.value) image_url = image_urls.get(image_id, "") print(image_url)