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 si je ne connais pas les feuilles disponibles?
Par exemple, je travaille avec des fichiers Excel que les feuilles suivantes
Données 1, Données 2 ..., Données N, toto, 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 les pandas?
Vous pouvez toujours utiliser la classe ExcelFile (et le sheet_names
attribut):
xl = pd.ExcelFile('foo.xls')
xl.sheet_names # see all sheet names
xl.parse(sheet_name) # read a specific sheet to DataFrame
voir docs for parse pour plus d'options ...
Vous devez explicitement spécifier le deuxième paramètre (nom de la feuille) en tant que Aucun. comme ça:
df = pandas.read_Excel("/yourPath/FileName.xlsx", None);
"df" sont toutes des feuilles sous forme de dictionnaire de DataFrames, vous pouvez le vérifier en exécutant ceci:
df.keys()
résultat comme ceci:
[u'201610', u'201601', u'201701', u'201702', u'201703', u'201704', u'201705', u'201706', u'201612', u'fund', u'201603', u'201602', u'201605', u'201607', u'201606', u'201608', u'201512', u'201611', u'201604']
veuillez consulter pandas doc pour plus de détails: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_Excel.html
En vous appuyant sur la réponse de @dhwanil_shah, vous n'avez pas besoin d'extraire l'intégralité du fichier. Avec zf.open
il est possible de lire directement à partir d’un fichier compressé.
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 readline
s consécutifs sont laids, mais le contenu ne figure que dans la deuxième ligne du texte. Pas besoin d'analyser le fichier entier.
Cette solution semble être beaucoup plus rapide que le read_Excel
version, et probablement aussi plus rapide que la version d'extrait complet.
J'ai essayé xlrd, pandas, openpyxl et d'autres bibliothèques similaires, et toutes semblent prendre un temps exponentiel à mesure que la taille du fichier augmente, à mesure qu'il lit l'intégralité du fichier. Les autres solutions mentionnées ci-dessus où ils utilisaient 'on_demand' ne fonctionnaient pas pour moi. Si vous voulez juste obtenir les noms de 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
Étant donné que tous les xlsx sont essentiellement des fichiers compressés, nous extrayons les données xml sous-jacentes et lisons directement les noms des feuilles dans le classeur, ce qui prend une fraction de seconde par rapport aux fonctions de la bibliothèque.
Analyse comparative: (sur un fichier xlsx de 6 Mo avec 4 feuilles)
Pandas, xlrd: 12 secondes
openpyxl: 24 secondes
Méthode proposée: 0.4 secondes
Puisque mon exigence consistait simplement à lire les noms des feuilles, la surcharge inutile de lire tout le temps me causait des problèmes, alors j’ai pris cette voie à la place.