283 votes

Pandas : Recherche de la liste des feuilles dans un fichier Excel

La nouvelle version de Pandas utilise l'interface suivante pour charger des fichiers Excel :

read_excel('path_to_file.xls', 'Sheet1', index_col=None, na_values=['NA'])

mais que faire si je ne connais pas les feuilles qui sont disponibles ?

Par exemple, je travaille avec des fichiers Excel contenant les feuilles suivantes

Données 1, Données 2 ..., Données N, foo, bar

mais je ne sais pas N a priori.

Existe-t-il un moyen d'obtenir la liste des feuilles d'un document Excel dans Pandas ?

4voto

Glen Thompson Points 1231

Si vous :

  • se soucient de la performance
  • n'ont pas besoin des données du fichier au moment de l'exécution.
  • vous souhaitez utiliser des bibliothèques conventionnelles ou développer votre propre solution.

L'évaluation ci-dessous a été effectuée sur un ordinateur de ~10Mb xlsx , xlsb fichier.

xlsx, xls

from openpyxl import load_workbook

def get_sheetnames_xlsx(filepath):
    wb = load_workbook(filepath, read_only=True, keep_links=False)
    return wb.sheetnames

Repères : ~ Amélioration de la vitesse de 14x

# get_sheetnames_xlsx vs pd.read_excel
225 ms ± 6.21 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
3.25 s ± 140 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

xlsb

from pyxlsb import open_workbook

def get_sheetnames_xlsb(filepath):
  with open_workbook(filepath) as wb:
     return wb.sheets

Repères : ~ Amélioration de la vitesse de 56x

# get_sheetnames_xlsb vs pd.read_excel
96.4 ms ± 1.61 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
5.36 s ± 162 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Notas:

3voto

Dhwanil shah Points 408

J'ai essayé xlrd, pandas, openpyxl et d'autres bibliothèques de ce type, mais toutes semblent prendre un temps exponentiel à mesure que la taille du fichier augmente, car elles lisent le fichier entier. Les autres solutions mentionnées ci-dessus, qui utilisent "on_demand", n'ont pas fonctionné pour moi. Si vous souhaitez simplement obtenir les noms des feuilles au départ, la fonction suivante fonctionne pour les fichiers xlsx.

def get_sheet_details(file_path):
    sheets = []
    file_name = os.path.splitext(os.path.split(file_path)[-1])[0]
    # Make a temporary directory with the file name
    directory_to_extract_to = os.path.join(settings.MEDIA_ROOT, file_name)
    os.mkdir(directory_to_extract_to)

    # Extract the xlsx file as it is just a zip file
    zip_ref = zipfile.ZipFile(file_path, 'r')
    zip_ref.extractall(directory_to_extract_to)
    zip_ref.close()

    # Open the workbook.xml which is very light and only has meta data, get sheets from it
    path_to_workbook = os.path.join(directory_to_extract_to, 'xl', 'workbook.xml')
    with open(path_to_workbook, 'r') as f:
        xml = f.read()
        dictionary = xmltodict.parse(xml)
        for sheet in dictionary['workbook']['sheets']['sheet']:
            sheet_details = {
                'id': sheet['@sheetId'],
                'name': sheet['@name']
            }
            sheets.append(sheet_details)

    # Delete the extracted files directory
    shutil.rmtree(directory_to_extract_to)
    return sheets

Comme tous les xlsx sont essentiellement des fichiers zippés, nous extrayons les données xml sous-jacentes et lisons les noms des feuilles du classeur directement, ce qui prend une fraction de seconde par rapport aux fonctions de la bibliothèque.

Benchmarking : (Sur un fichier xlsx de 6mb avec 4 feuilles)
Pandas, xlème : 12 secondes
openpyxl : 24 secondes
Méthode proposée : 0,4 seconde

Comme je devais simplement lire les noms des feuilles, le fait de devoir lire tout le temps me dérangeait et j'ai donc choisi cette voie.

3voto

divingTobi Points 54

Dans le prolongement de la réponse de @dhwanil_shah, vous n'avez pas besoin d'extraire le fichier entier. Avec zf.open il est possible de lire directement à partir d'un fichier zippé.

import xml.etree.ElementTree as ET
import zipfile

def xlsxSheets(f):
    zf = zipfile.ZipFile(f)

    f = zf.open(r'xl/workbook.xml')

    l = f.readline()
    l = f.readline()
    root = ET.fromstring(l)
    sheets=[]
    for c in root.findall('{http://schemas.openxmlformats.org/spreadsheetml/2006/main}sheets/*'):
        sheets.append(c.attrib['name'])
    return sheets

Les deux années consécutives readline sont moches, mais le contenu ne se trouve que sur la deuxième ligne du texte. Il n'est pas nécessaire d'analyser le fichier entier.

Cette solution semble être beaucoup plus rapide que la read_excel et très probablement aussi plus rapide que la version intégrale de l'extrait.

3voto

zzhapar Points 37

Si vous lisez le fichier excel

dfs = pd.ExcelFile('file')

puis utiliser

dfs.sheet_names
dfs.parse('sheetname')

une autre variante

df = pd.read_excel('file', sheet_name='sheetname')

2voto

flutefreak7 Points 349
from openpyxl import load_workbook

sheets = load_workbook(excel_file, read_only=True).sheetnames

Pour un fichier Excel de 5MB avec lequel je travaille, load_workbook sans le read_only Le drapeau a pris 8.24s. Avec le read_only flag, il n'a fallu que 39,6 ms. Si vous voulez toujours utiliser une bibliothèque Excel et ne pas passer à une solution xml, c'est beaucoup plus rapide que les méthodes qui analysent le fichier entier.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X