簡體   English   中英

如何使用Python讀取包含擴展fonts的Excel文件? (openpyxl 錯誤:最大值為 14)

[英]How to use Python to read Excel files that contain extended fonts? (openpyxl error: Max value is 14)

作為 Python 的學習項目,我試圖讀取目錄中的所有 Excel 文件並提取所有工作表的名稱。

我一直在嘗試幾個可用的 Python 模塊來執行此操作(在本例中為pandas ),但我遇到了一個問題,其中大部分取決於openpyxl

這是我當前的代碼:

import os
import pandas

directory_root = 'D:\\testFiles'

# Dict to hold all files, stats
all_files = {}

for _current_path, _dirs_in_path, _files_in_path in os.walk(directory_root):

    # Add all files to this `all_files`
    for _file in _files_in_path:
        # Extract filesystem stats from the file
        _stats = os.stat(os.path.join(_current_path, _file))

        # Add the full file path and its stats to the `all_files` dict.
        all_files[os.path.join(_current_path, _file)] = _stats

# Loop through all found files to extract the sheet names
for _file in all_files:

    # Open the workbook
    xls = pandas.ExcelFile(_file)

    # Loop through all sheets in the workbook
    for _sheet in xls.sheet_names():
        print(_sheet)

這會在調用pandas.ExcelFile()時從openpyxl引發錯誤: ValueError: Max value is 14

根據我在網上可以找到的信息,這是因為該文件包含 14 以上的字體系列。如何在忽略任何現有格式的情況下讀取 Excel (xlsx) 文件?

我能找到的唯一可能的解決方案是修改原始文件並刪除格式,但這不是一個選項,因為我不想以任何方式修改文件。

還有另一種沒有格式限制的方法嗎?

通過在 windows 或 grep 中的簡單解壓縮|查找,很容易檢測到家庭值何時超出范圍。 因此,您可以根據這些值過濾掉文件。 在這里,我們在 bad boy 示例中看到它們是可以接受的 2 和不可接受的 34

在此處輸入圖像描述

但是,由於所有平台(包括 win 10)都有 TAR,因此最簡單的方法是首先將 file.xlsx 擴展為一組並在本機操作系統(或 python)中使用按文件查找,然后確保您確切知道需要調整哪個文件。

在此處輸入圖像描述

所以我們現在知道它是 styles.xml(這並不奇怪,因為字體值應該在那里)

此時我們可以使用字符串替換來更改該條目說

      <family val="3"/>

如果這對您的目的更有用。

然后重新打包調整后的 xlsx(注意:最好只使用工具“更新”一個 style.xls 文件以維護 zip 的相對順序),它的行為應該與具有標准的 standard.xlsx 相同1-14 fonts,假設作者沒有引入其他錯誤。

這很可能不是因為字體大小或系列,因為它給出了 ValueError。 我從這個頁面這個頁面看到的,似乎你在 excel 文件中的一個浮點值不能超過 14。這就是它給出錯誤ValueError: Max value is 14的原因。 您可以深入該文件並搜索大於 14 的值,然后通過操作該值來嘗試您的代碼。

問題是您的文件不符合 Open Office 規范。 僅允許使用某些字體系列。 一旦openpyxl遇到不符合規范的字體,它就會拋出這個錯誤,因為OpenPyxl 只允許符合規范的 excel 文件

一些 Excel 閱讀器可能對此沒有問題,並且對不符合 OpenOffice 規范的文件更靈活,但 openpyxl 僅實現 Apache Open Office 規范。

正在解析的 xml 將包含有關字體的信息,如下所示:

<font>
  <b/>
  <sz val="11"/>
  <color rgb="FF000000"/>
  <name val="Century Gothic"/>
  <family val="34"/>
</font>

如果家庭值超過 14,openpyxl 會拋出這個ValueError Open Office 中有一個底層描述符來控制它。

當其他讀者(例如 Microsoft Office 365 Excel)遇到這種情況時,它會在將文件加載為兼容字體(默認為 Calibri)時更改字體系列。

作為一種解決方法,如果您不想更改該值(如 Microsoft Excel 所做的那樣),您可以對描述符進行猴子補丁以允許更大的最大字體系列。

# IMPORTANT, you must do this before importing openpyxl
from unittest import mock
# Set max font family value to 100
p = mock.patch('openpyxl.styles.fonts.Font.family.max', new=100)
p.start()
import openpyxl
openpyxl.open('my-bugged-worksheet.xlsx') # this works now!

這可以使用此 excel 工作簿進行復制。 在補丁之前,這將無法加載。 補丁后,它加載沒有錯誤。

這是為我解決此錯誤的原因。 我編輯了lib\site-packages\openpyxl\descriptors\base.py並在 class Max 的第86行之后添加了一個打印語句,如下所示:

def __set__(self, instance, value):
    if ((self.allow_none and value is not None)
        or not self.allow_none):
        value = _convert(self.expected_type, value)
        if value > self.max:
            print(f"value is {value}")
            raise ValueError('Max value is {0}'.format(self.max))
    super(Max, self).__set__(instance, value)

這打印出34的值,明顯高於最大值 14。
我所做的只是注釋掉raise錯誤的行。
將代碼更改為:

def __set__(self, instance, value):
    if ((self.allow_none and value is not None)
        or not self.allow_none):
        value = _convert(self.expected_type, value)
        if value > self.max:
            self.max = value
            # print(f"value is {value}")
            # raise ValueError('Max value is {0}'.format(self.max))
    super(Max, self).__set__(instance, value)

這為我解決了這個問題。
或者,如果您需要分發文件並且必須使用原始庫代碼,那么請嘗試第一個答案

# IMPORTANT, you must do this before importing openpyxl
from unittest import mock
# Set max font family value to 100
p = mock.patch('openpyxl.styles.fonts.Font.family.max', new=100)
p.start()
import openpyxl
openpyxl.open('my-bugged-worksheet.xlsx') # this works now!

在導入 openpyxl 之前。

如果我是對的,您想從目錄中的文件中獲取所有 xlsx 工作表名稱,以便您可以執行以下操作:

import pandas as pd
import os
dirpth = './Target Folder/'
for dirpath, dirnames, filenames in os.walk(dirpth):
    file_names = filenames
file_names = [dirpth+file_names[i] for i in range(len(file_names))]
data = []
sheet_names = []
for names in file_names:
    df = pd.ExcelFile(names,engine = 'openpyxl')
    data_sheet = []
    sheet_temp = []
    for name in df.sheet_names:
        data_sheet.append(df.parse(nama,index_col = [0]))
        sheet_temp.append(name)
    data.append(data_sheet)
    sheet_names.append(sheet_temp)

這樣,您將自動從每個工作表中獲取每個 excel 文件的數據,但是如果您在同一文件夾中具有不同擴展名的文件(例如在同一文件夾中您有.csv 文件),則會出現錯誤。 因此,您需要先過濾所有文件名,或者您可以使用try except語句跳過非 excel 文件。 如果您的.py 文件與您的文件夾目標路徑不同,只需更改 dirpath,例如: 'D:/changeYour Folder Path/Example/Target/'

注意:需要安裝openpyxl

這個問題可以通過完全清理 xlsx styles來解決,這是我的代碼如何使用pandas通過openpyxl https://stackoverflow.com/a/71526058/1731460

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM