Pandas: Consultando a lista de planilhas em um arquivo do Excel

144

A nova versão do Pandas usa a seguinte interface para carregar arquivos do Excel:

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

mas e se eu não souber as folhas disponíveis?

Por exemplo, estou trabalhando com arquivos do Excel que as folhas a seguir

Dados 1, Dados 2 ..., Dados N, foo, bar

mas eu não sei Na priori.

Existe alguma maneira de obter a lista de planilhas de um documento do Excel no Pandas?

Amelio Vazquez-Reina
fonte

Respostas:

253

Você ainda pode usar a classe ExcelFile (e o sheet_namesatributo):

xl = pd.ExcelFile('foo.xls')

xl.sheet_names  # see all sheet names

xl.parse(sheet_name)  # read a specific sheet to DataFrame

consulte os documentos para analisar para obter mais opções ...

Andy Hayden
fonte
1
Obrigado @Andy. Posso perguntar: o Pandas carrega a planilha do Excel ExcelFile? Além disso, digamos que eu procure na lista de planilhas e decida carregar N delas, nesse momento devo chamar read_excel(a nova interface) para cada planilha ou seguir x1.parse?
Amelio Vazquez-Reina
2
Acho que o ExcelFile mantém o arquivo aberto (e não lê tudo), acho que usar a análise (e abrir o arquivo apenas uma vez) faz mais sentido aqui. tbh perdi a chegada do read_excel!
Andy Hayden
6
Mencionado antes aqui , mas eu gosto de manter um dicionário de DataFrames usando{sheet_name: xl.parse(sheet_name) for sheet_name in xl.sheet_names}
Andy Hayden
2
Gostaria de poder lhe dar mais votos, isso também funciona em várias versões de pandas! (não sei por que eles gostam de mudar a API com tanta frequência) Obrigado por me indicar a função de análise, aqui está o link atual: pandas.pydata.org/pandas-docs/stable/generated/…
Ezekiel Kruglick
3
@NicholasLu o voto negativo foi desnecessário, esta resposta é de 2013! Dito isto, embora o ExcelFile seja a maneira original de analisar arquivos do Excel, ele não é preterido e continua sendo uma maneira perfeitamente válida de fazer isso.
Andy Hayden
37

Você deve especificar explicitamente o segundo parâmetro (nome da planilha) como Nenhum. como isso:

 df = pandas.read_excel("/yourPath/FileName.xlsx", None);

"df" são todas as planilhas como um dicionário de DataFrames, você pode verificá-lo executando o seguinte:

df.keys()

resultado como este:

[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']

consulte o documento do pandas para obter mais detalhes: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_excel.html

Nicholas Lu
fonte
3
Isso analisa desnecessariamente todas as planilhas como um DataFrame, o que não é necessário. "Como ler um arquivo xls / xlsx" é uma pergunta diferente .
Andy Hayden
7
@AndyHayden pode não ser eficiente, mas pode ser o melhor se você se preocupa com todas as folhas ou se não se preocupa com a sobrecarga adicional.
precisa saber é o seguinte
8

Esta é a maneira mais rápida que encontrei, inspirada na resposta do @ divingTobi. Todas As respostas baseadas em xlrd, openpyxl ou pandas são lentas para mim, pois todas elas carregam o arquivo inteiro primeiro.

from zipfile import ZipFile
from bs4 import BeautifulSoup  # you also need to install "lxml" for the XML parser

with ZipFile(file) as zipped_file:
    summary = zipped_file.open(r'xl/workbook.xml').read()
soup = BeautifulSoup(summary, "xml")
sheets = [sheet.get("name") for sheet in soup.find_all("sheet")]
MAR
fonte
3

Com base na resposta de @dhwanil_shah, você não precisa extrair o arquivo inteiro. Com zf.openisso, é possível ler diretamente de um arquivo compactado.

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

Os dois readlines consecutivos são feios, mas o conteúdo está apenas na segunda linha do texto. Não há necessidade de analisar o arquivo inteiro.

Essa solução parece ser muito mais rápida que a read_excelversão e, provavelmente, também mais rápida que a versão de extração completa.

divingTobi
fonte
Não, o .xls é um formato de arquivo completamente diferente, portanto, eu não esperaria que esse código funcionasse.
divingTobi
2

Eu tentei xlrd, pandas, openpyxl e outras bibliotecas desse tipo e todas parecem demorar um tempo exponencial à medida que o tamanho do arquivo aumenta à medida que lê o arquivo inteiro. As outras soluções mencionadas acima, onde eles usaram 'on_demand', não funcionaram para mim. Se você deseja apenas obter os nomes das planilhas inicialmente, a função a seguir funciona para arquivos 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

Como todos os xlsx são basicamente arquivos compactados, extraímos os dados xml subjacentes e lemos os nomes das planilhas diretamente da pasta de trabalho, o que leva uma fração de segundo em comparação com as funções da biblioteca.

Benchmarking: (em um arquivo xlsx de 6mb com 4 folhas)
Pandas, xlrd: 12 segundos
openpyxl: 24 segundos
Método proposto: 0,4 segundos

Como minha exigência era apenas ler os nomes das planilhas, a sobrecarga desnecessária de ler o tempo todo estava me incomodando, então eu segui essa rota.

Dhwanil shah
fonte
Quais são os módulos que você está usando?
Daniel
@ Daniel Eu usei apenas o zipfileque é um módulo embutido e o xmltodictusado para converter o XML em um dicionário facilmente iterável. Embora você possa ver a resposta do @ divingTobi abaixo, você pode ler o mesmo arquivo sem extrair os arquivos.
Dhwanil shah
Quando tentei o openpyxl com o sinalizador read_only, é significativamente mais rápido (200X mais rápido para o meu arquivo de 5 MB). load_workbook(excel_file).sheetnamesem média 8,24s, em load_workbook(excel_file, read_only=True).sheetnamesmédia, 39,6ms.
flutefreak7
0
from openpyxl import load_workbook

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

Para um arquivo do Excel de 5 MB em que estou trabalhando, load_workbooksem o read_onlysinalizador demorou 8,24s. Com a read_onlybandeira, foram necessários apenas 39,6 ms. Se você ainda deseja usar uma biblioteca do Excel e não usar uma solução xml, isso é muito mais rápido que os métodos que analisam o arquivo inteiro.

flutefreak7
fonte