Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

741
Vistas
¿Cómo usar Python para leer archivos de Excel que contienen fuentes extendidas? (error de openpyxl: el valor máximo es 14)

Como proyecto de aprendizaje para Python, intento leer todos los archivos de Excel en un directorio y extraer los nombres de todas las hojas.

He estado probando varios módulos de Python disponibles para hacer esto ( pandas en este ejemplo), pero tengo un problema con la mayoría de ellos que dependen de openpyxl .

Este es mi código actual:

 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)

Esto genera un error de openpyxl al llamar a pandas.ExcelFile() : ValueError: Max value is 14 .

Por lo que puedo encontrar en línea, esto se debe a que el archivo contiene una familia de fuentes superior a 14. ¿Cómo leo un archivo de Excel (xlsx) sin tener en cuenta el formato existente?

La única solución potencial que pude encontrar sugiere modificar el archivo original y eliminar el formato, pero esta no es una opción ya que no quiero modificar los archivos de ninguna manera.

¿Hay otra forma de hacer esto que no tenga esta limitación de formato?

over 4 years ago · Santiago Trujillo
3 Respuestas
Responde la pregunta

0

El problema es que su archivo no se ajusta a la especificación de Open Office. Solo se permiten ciertas familias de fuentes. Una vez que openpyxl encuentra una fuente fuera de especificación, arroja este error porque OpenPyxl solo permite archivos de Excel que cumplen con las especificaciones .

Es posible que algunos lectores de Excel no tengan problemas con esto y sean más flexibles con los archivos que no se ajustan a las especificaciones de OpenOffice, pero openpyxl solo implementa las especificaciones de Apache Open Office.

El xml que se analiza contendrá información sobre la fuente como esta:

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

Si el valor de la familia es superior a 14, openpyxl arroja este ValueError . Hay un descriptor subyacente en Open Office que controla esto.

Cuando otros lectores como, por ejemplo, Microsoft Office 365 Excel encuentran esto, cambiará la familia de fuentes al cargar el archivo a una fuente compatible (la predeterminada, Calibri).

Como solución alternativa, si no desea cambiar el valor (como lo hace Microsoft Excel), puede parchear el descriptor para permitir una familia de fuentes máxima más grande.

 # 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!

Esto se puede reproducir utilizando este libro de Excel . Antes del parche, esto no se cargará. Después del parche, carga sin error.

over 4 years ago · Santiago Trujillo Denunciar

0

Es fácil detectar cuándo el valor familiar está fuera de rango con un simple descomprimir|buscar en Windows o un grep en otros. Entonces podría filtrar archivos en función de esos valores. aquí vemos en el ejemplo del chico malo que son aceptables 2 y un inaceptable 34

ingrese la descripción de la imagen aquí

Sin embargo, dado que todas las plataformas (incluida Win 10) tienen TAR, es más fácil primero expandir el archivo.xlsx como un conjunto y usar la búsqueda por archivo en el sistema operativo nativo (o python), luego asegúrese de saber exactamente qué archivo necesita ajustar.

ingrese la descripción de la imagen aquí

Entonces ahora sabemos que es styles.xml (eso no es sorprendente ya que los valores de fuente deberían estar allí)

y en este punto podemos usar el reemplazo de cadena para cambiar esa entrada para decir

 <family val="3"/>

si eso es más útil para su propósito.

Luego vuelva a empacar el xlsx ajustado (NOTA: es mejor usar solo una herramienta para "actualizar" el archivo style.xls para mantener el orden relativo zip) y debería comportarse igual que un estándar.xlsx que tiene el estándar 1-14 fuentes, asumiendo que el autor no introdujo otros errores.

EDICIÓN POSTERIOR No pretendo reinventar una Rueda Pythonic, sino simplemente decir que desde https://stackoverflow.com/a/69360331/10802527 (por un usuario que ya no está) esto debería funcionar para muchos otros usuarios interesados. Haga una copia de seguridad de sus archivos y modifíquelos en consecuencia.

 import tempfile from openpyxl import load_workbook import os import shutil from lxml import etree EXCELFILE = '~/Book1.xlsx' STYLES = 'xl/styles.xml' FORMAT = 'zip' with tempfile.TemporaryDirectory() as tdir: os.chdir(tdir) shutil.unpack_archive(filename=EXCELFILE, format=FORMAT) with open(STYLES, 'r') as styles: tree = etree.parse(styles) for family in tree.xpath('//*[local-name()="fonts"]//*[local-name()="font"]//*[local-name()="family"]'): try: if int(family.attrib['val']) > 14: family.set('val', '2') except Exception: pass with open(STYLES, 'wb') as styles: tree.write(styles) shutil.make_archive(base_name=EXCELFILE, format=FORMAT) shutil.move(f'{EXCELFILE}.{FORMAT}', EXCELFILE) load_workbook(EXCELFILE)

La llamada a load_workbook() se realiza simplemente como una verificación de la validez de la hoja de cálculo modificada.

over 4 years ago · Santiago Trujillo Denunciar

0

Esto es lo que solucionó este error para mí. Edité lib\site-packages\openpyxl\descriptors\base.py y agregué una declaración de impresión después de la línea 86 en la clase Max así:

 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)

Esto imprimió el valor de 34 que obviamente es más alto que el valor máximo de 14.
Todo lo que hice para que funcionara fue comentar la línea que raise el error.
Cambiando el código a:

 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)

Esto resolvió mi problema.
O si necesita distribuir el archivo y tiene que usar el código de biblioteca original, ENTONCES intente con la primera respuesta .

 # 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!

Antes de importar openpyxl.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda