使用Python从Excel文件中提取图像

6

我有一个包含100行的Excel表格。每一行都包含不同的信息,包括ID和一个包含照片的单元格。

我使用Pandas将数据加载到字典中:

import pandas as pd

df = pd.read_excel('myfile.xlsx')

data = []

for index,row in df.iterrows():
    data.append({
        'id':row['id'],
        'field2':row['field2'],
        'field3':row['field3']
    })

对于图片列,我想提取每个图像,用该行的ID命名(image_row['id'].jpg),并将其放入一个文件夹中。 然后,我希望将图像的路径存储如下:
for index,row in df.iterrows():
        data.append({
            'id':row['id'],
            'field2':row['field2'],
            'field3':row['field3'],
            'image':'path/image_'+row['id']+'.jpg'
        })

我正在寻找一种方法来实现这个目标,如果有更好的方法也可以。你有什么想法吗?

我使用的是Linux系统,所以不能使用这种基于pywin32的方法

非常感谢。

-- 编辑

在这里你可以找到我使用的表格示例。

4个回答

25

我找到了一个使用openpyxlopenpyxl-image-loader模块的解决方案。

# installing the modules
pip3 install openpyxl
pip3 install openpyxl-image-loader

然后,在脚本中:

#Importing the modules
import openpyxl
from openpyxl_image_loader import SheetImageLoader

#loading the Excel File and the sheet
pxl_doc = openpyxl.load_workbook('myfile.xlsx')
sheet = pxl_doc['Sheet_name']

#calling the image_loader
image_loader = SheetImageLoader(sheet)

#get the image (put the cell you need instead of 'A1')
image = image_loader.get('A1')

#showing the image
image.show()

#saving the image
image.save('my_path/image_name.jpg')
最后,我可以在循环中为每一行存储路径和图像名称到我的字典中。

1
这个已经不起作用了。因为当我们调用 SheetImageLoader(sheet) 时,它内部会调用 sheet._image,而现在该属性不可用了。 - a b
我正在使用Openpyxl 3.1.2(以及openpyxl-image-loader 1.0.5),这是目前最新的版本。工作表对象仍然存在._image属性,所以这段代码仍然有效。也许它曾经出现过问题,但现在已经修复了。 - moken
仍然为我工作! - undefined

6
def extract_images_from_excel(path, dir_extract=None):
    """extracts images from excel and names then with enumerated filename
    
    Args:
        path: pathlib.Path, excel filepath
        dir_extract: pathlib.Path, default=None, defaults to same dir as excel file
    
    Returns:
        new_paths: list[pathlib.Path], list of paths to the extracted images
    """
    if type(path) is str:
        path = pathlib.Path(path)
    if dir_extract is None:
        dir_extract = path.parent
    if path.suffix != '.xlsx':
        raise ValueError('path must be an xlsx file')
    name = path.name.replace(''.join(path.suffixes), '').replace(' ', '') # name of excel file without suffixes
    temp_file = pathlib.Path(source_file).parent / 'temp.xlsx' # temp xlsx
    temp_zip = temp_file.with_suffix('.zip') # temp zip
    shutil.copyfile(source_file, temp_file)
    temp_file.rename(str(temp_zip))
    extract_dir =  temp_file.parent / 'temp'
    extract_dir.mkdir(exist_ok=True)
    shutil.unpack_archive(temp_zip, extract_dir) # unzip xlsx zip file
    paths_img = sorted((extract_dir / 'xl' / 'media').glob('*.png')) # find images
    move_paths = {path: destination_dir / (name + f'-{str(n)}.png') for n, path in enumerate(paths_img)} # create move path dict 
    new_paths = [shutil.move(old, new) for old, new in move_paths.items()] # move / rename image files
    shutil.rmtree(extract_dir) # delete temp folder
    temp_zip.unlink() # delete temp file
    return new_paths

以上操作含义如下:

  • 复制Excel文件
  • 解压缩文件
  • 从Excel中提取图像到临时文件夹
  • 移动并重命名图像
  • 删除临时文件夹和文件

不需要第三方软件包,也不需要Windows运行。


它在一些修改(替换一些变量)后完美地运行了,非常感谢! - Arnaud Hureaux

2
您可以解压已重命名的xlsx zip文件。
$ cp a.xlsx a.zip

$ unzip a.zip

$ ls -al xl/media

2

可能有更好的解决方案,但我认为如果这已经足够好了,我可以分享我所知道的。


Excel的.xlsx文件实际上是一个zip文件。因此,您可以使用7z或Python Zipfile读取它。在终端中演示如下:

# List contents
7z l a.xlsx

7-Zip [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=utf8,Utf16=on,HugeFiles=on,64 bits,12 CPUs x64)

Scanning the drive for archives:
1 file, 596240 bytes (583 KiB)

Listing archive: a.xlsx

--
Path = a.xlsx
Type = zip
Physical Size = 596240

   Date      Time    Attr         Size   Compressed  Name
------------------- ----- ------------ ------------  ------------------------
2020-05-27 02:36:54 .....         2371          563  xl/drawings/drawing1.xml
2020-05-27 02:36:54 .....          561          198  xl/drawings/_rels/drawing1.xml.rels
2020-05-27 02:36:54 .....         1781          565  xl/worksheets/sheet1.xml
2020-05-27 02:36:54 .....          298          179  xl/worksheets/_rels/sheet1.xml.rels
2020-05-27 02:36:54 .....         3757          808  xl/theme/theme1.xml
2020-05-27 02:36:54 .....          427          204  xl/sharedStrings.xml
2020-05-27 02:36:54 .....         2523          613  xl/styles.xml
2020-05-27 02:36:54 .....          809          330  xl/workbook.xml
2020-05-27 02:36:54 .....          697          234  xl/_rels/workbook.xml.rels
2020-05-27 02:36:54 .....          296          178  _rels/.rels
2020-05-27 02:36:54 .....       156683       156657  xl/media/image2.png
2020-05-27 02:36:54 .....        46848        46853  xl/media/image1.png
2020-05-27 02:36:54 .....       386512       386632  xl/media/image3.png
2020-05-27 02:36:54 .....         1099          320  [Content_Types].xml
------------------- ----- ------------ ------------  ------------------------
2020-05-27 02:36:54             604662       594334  14 files

您可以提取文件并使用以下命令查看图像:
7z x a.xlsx

另一个选项可能是将Excel文件保存为PDF,然后可以从Poppler软件包中运行pdfimages并提取图像:

pdfimages -png YourSpreadsheet.pdf extracted

示例输出
-rw-r--r--@ 1 mark  staff   92973 27 May 10:57 extracted-000.png
-rw-r--r--@ 1 mark  staff   28074 27 May 10:57 extracted-001.png
-rw-r--r--@ 1 mark  staff     189 27 May 10:57 extracted-002.png
-rw-r--r--@ 1 mark  staff  244898 27 May 10:57 extracted-003.png

谢谢,我确实可以用这种方法提取所有图像。你知道怎么在我的Python数据框中保留每行媒体的名称吗?我在帖子中使用的方法总是将照片的单元格视为“nan”。 - Cupain
抱歉,我不知道。 - Mark Setchell

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接