[{"data":1,"prerenderedAt":2037},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Flist-sheet-names-and-column-headers-without-loading-data":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Flist-sheet-names-and-column-headers-without-loading-data":2002,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Flist-sheet-names-and-column-headers-without-loading-data":2011,"children:\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Flist-sheet-names-and-column-headers-without-loading-data":2016,"related:\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Flist-sheet-names-and-column-headers-without-loading-data":2017},{"id":4,"title":5,"body":6,"dateModified":1967,"datePublished":1967,"description":1968,"extension":1969,"faq":1970,"keyword":1979,"kind":1980,"meta":1981,"navigation":248,"path":1991,"seo":1992,"slug":1995,"stem":1996,"topics":1997,"type":2000,"__hash__":2001},"docs\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Flist-sheet-names-and-column-headers-without-loading-data\u002Findex.md","List Sheet Names and Column Headers Without Loading the Data",{"type":7,"value":8,"toc":1954},"minimark",[9,24,29,57,83,202,206,212,323,337,340,455,484,488,503,685,695,781,796,800,811,905,930,934,937,1234,1260,1472,1476,1491,1756,1765,1777,1781,1860,1864,1871,1875,1885,1889,1899,1905,1911,1917,1921,1950],[10,11,12,13,17,18,23],"p",{},"Before a script reads a workbook it often needs to know what is in it: which sheets exist, which one holds the data, what the columns are called, roughly how many rows there are. Reading every sheet with ",[14,15,16],"code",{},"pd.read_excel(sheet_name=None)"," answers all of that, but it parses every cell of every sheet to do so — seconds per file, minutes for a folder. The workbook already records most of this in small metadata parts, and pandas and openpyxl can read them without touching the data. This page, part of ",[19,20,22],"a",{"href":21},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002F","Reading Excel Files with pandas",", shows the fast way to inspect a file and then builds a catalogue of a whole folder.",[25,26,28],"h2",{"id":27},"prerequisites","Prerequisites",[30,31,36],"pre",{"className":32,"code":33,"language":34,"meta":35,"style":35},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[14,37,38],{"__ignoreMap":35},[39,40,43,47,51,54],"span",{"class":41,"line":42},"line",1,[39,44,46],{"class":45},"sMTad","pip",[39,48,50],{"class":49},"srMev"," install",[39,52,53],{"class":49}," pandas",[39,55,56],{"class":49}," openpyxl\n",[10,58,59,62,63,66,67,70,71,74,75,78,79,82],{},[14,60,61],{},"sales_2025.xlsx"," has an ",[14,64,65],{},"Orders"," sheet with 200,000 rows, a hidden ",[14,68,69],{},"Lookup"," sheet, a ",[14,72,73],{},"Summary"," sheet and a chartsheet called ",[14,76,77],{},"Chart",". The ",[14,80,81],{},"exports\u002F"," folder holds three store workbooks, one of which has a column renamed.",[84,85,93,94,93,98,93,102,93,110,93,120,93,131,93,138,93,143,93,146,93,152,93,156,93,160,93,165,93,172,93,177,93,181,93,186,93,193,93,198],"svg",{"viewBox":86,"role":87,"ariaLabelledBy":88,"xmlns":91,"style":92},"64 0 632 434","img",[89,90],"sh-parts-t","sh-parts-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:632px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[95,96,97],"title",{"id":89},"What each question costs to answer",[99,100,101],"desc",{"id":90},"Layers of an xlsx file from cheapest to read to most expensive. Sheet names come from workbook.xml, the used range from each sheet's dimension record, the header from the first row, and the full data from every row.",[103,104],"rect",{"x":105,"y":106,"width":107,"height":108,"fill":109},"64","0","632","434","#ffffff",[103,111],{"x":112,"y":113,"width":114,"height":115,"rx":116,"fill":117,"stroke":118,"style":119},"80.0","16.0","600.0","93.0","12","#d9f4f1","var(--teal,#0f9488)","stroke-width:2px",[121,122,124],"g",{"transform":123},"translate(368.0,29.0) scale(1.000)",[125,126],"path",{"d":127,"fill":128,"stroke":129,"style":130},"M6 3h9l4 4v14H6z M15 3v4h4","none","var(--teal-ink,#0b6157)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[132,133,137],"text",{"x":134,"y":135,"style":136},"380.0","75.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Sheet names and visibility",[132,139,142],{"x":134,"y":140,"style":141},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","xl\u002Fworkbook.xml — a few hundred bytes",[103,144],{"x":112,"y":145,"width":114,"height":115,"rx":116,"fill":117,"stroke":118,"style":119},"119.0",[121,147,149],{"transform":148},"translate(368.0,132.0) scale(1.000)",[125,150],{"d":151,"fill":128,"stroke":129,"style":130},"M4 4h16v16H4z M4 9h16 M4 14h16 M10 4v16",[132,153,155],{"x":134,"y":154,"style":136},"178.5","Used range",[132,157,159],{"x":134,"y":158,"style":141},"198.0","the \u003Cdimension> record at the top of each sheet",[103,161],{"x":112,"y":162,"width":114,"height":115,"rx":116,"fill":163,"stroke":164,"style":119},"222.0","#f0f4ff","var(--brand,#5b5cf0)",[121,166,168],{"transform":167},"translate(368.0,235.0) scale(1.000)",[125,169],{"d":170,"fill":128,"stroke":171,"style":130},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","var(--brand-strong,#4338ca)",[132,173,176],{"x":134,"y":174,"style":175},"281.5","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Header row",[132,178,180],{"x":134,"y":179,"style":141},"301.0","first row only — stop reading after it",[103,182],{"x":112,"y":183,"width":114,"height":115,"rx":116,"fill":184,"stroke":185,"style":119},"325.0","#fdefd8","var(--gold,#b4740a)",[121,187,189],{"transform":188},"translate(368.0,338.0) scale(1.000)",[125,190],{"d":191,"fill":128,"stroke":192,"style":130},"M5 6c0-1.7 3.1-3 7-3s7 1.3 7 3-3.1 3-7 3-7-1.3-7-3z M5 6v12c0 1.7 3.1 3 7 3s7-1.3 7-3V6 M5 12c0 1.7 3.1 3 7 3s7-1.3 7-3","var(--gold-ink,#7a4e06)",[132,194,197],{"x":134,"y":195,"style":196},"384.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Every cell",[132,199,201],{"x":134,"y":200,"style":141},"404.0","the whole sheet XML — what a full read_excel parses",[25,203,205],{"id":204},"step-1-list-the-sheet-names","Step 1 — List the sheet names",[10,207,208,211],{},[14,209,210],{},"pd.ExcelFile"," opens the workbook and reads its list of sheets without parsing any of them:",[30,213,217],{"className":214,"code":215,"language":216,"meta":35,"style":35},"language-python shiki shiki-themes github-light github-dark-high-contrast","import time\nimport pandas as pd\n\nt = time.perf_counter()\nwith pd.ExcelFile(\"sales_2025.xlsx\") as xl:\n    print(xl.sheet_names, f\"{time.perf_counter() - t:.3f}s\")\n","python",[14,218,219,229,243,250,262,282],{"__ignoreMap":35},[39,220,221,225],{"class":41,"line":42},[39,222,224],{"class":223},"s-kum","import",[39,226,228],{"class":227},"skGVy"," time\n",[39,230,232,234,237,240],{"class":41,"line":231},2,[39,233,224],{"class":223},[39,235,236],{"class":227}," pandas ",[39,238,239],{"class":223},"as",[39,241,242],{"class":227}," pd\n",[39,244,246],{"class":41,"line":245},3,[39,247,249],{"emptyLinePlaceholder":248},true,"\n",[39,251,253,256,259],{"class":41,"line":252},4,[39,254,255],{"class":227},"t ",[39,257,258],{"class":223},"=",[39,260,261],{"class":227}," time.perf_counter()\n",[39,263,265,268,271,274,277,279],{"class":41,"line":264},5,[39,266,267],{"class":223},"with",[39,269,270],{"class":227}," pd.ExcelFile(",[39,272,273],{"class":49},"\"sales_2025.xlsx\"",[39,275,276],{"class":227},") ",[39,278,239],{"class":223},[39,280,281],{"class":227}," xl:\n",[39,283,285,289,292,295,298,302,305,308,311,314,317,320],{"class":41,"line":284},6,[39,286,288],{"class":287},"sP0c6","    print",[39,290,291],{"class":227},"(xl.sheet_names, ",[39,293,294],{"class":223},"f",[39,296,297],{"class":49},"\"",[39,299,301],{"class":300},"sSjpA","{",[39,303,304],{"class":227},"time.perf_counter() ",[39,306,307],{"class":223},"-",[39,309,310],{"class":227}," t",[39,312,313],{"class":223},":.3f",[39,315,316],{"class":300},"}",[39,318,319],{"class":49},"s\"",[39,321,322],{"class":227},")\n",[10,324,325,326,329,330,332,333,336],{},"Use ",[14,327,328],{},"ExcelFile"," as a context manager so the file is closed afterwards; left open, Python warns about an unclosed file and Windows keeps the workbook locked. Inside the ",[14,331,267],{}," block the same object can read any sheet with ",[14,334,335],{},"xl.parse(\"Orders\")",", reusing the open file instead of opening it again — useful when the next step is to read one or two of the sheets it just listed.",[10,338,339],{},"The chartsheet is missing from that list: pandas lists only worksheets, because a chartsheet has no cells to read. openpyxl in read-only mode shows everything, and says which sheets are hidden:",[30,341,343],{"className":214,"code":342,"language":216,"meta":35,"style":35},"from openpyxl import load_workbook\n\nwb = load_workbook(\"sales_2025.xlsx\", read_only=True)\nprint(\"all sheets:\", wb.sheetnames)\nfor ws in wb.worksheets:\n    print(f\"  {ws.title:8} {ws.sheet_state}\")\nwb.close()\n",[14,344,345,358,362,388,402,416,449],{"__ignoreMap":35},[39,346,347,350,353,355],{"class":41,"line":42},[39,348,349],{"class":223},"from",[39,351,352],{"class":227}," openpyxl ",[39,354,224],{"class":223},[39,356,357],{"class":227}," load_workbook\n",[39,359,360],{"class":41,"line":231},[39,361,249],{"emptyLinePlaceholder":248},[39,363,364,367,369,372,374,377,381,383,386],{"class":41,"line":245},[39,365,366],{"class":227},"wb ",[39,368,258],{"class":223},[39,370,371],{"class":227}," load_workbook(",[39,373,273],{"class":49},[39,375,376],{"class":227},", ",[39,378,380],{"class":379},"sa561","read_only",[39,382,258],{"class":223},[39,384,385],{"class":287},"True",[39,387,322],{"class":227},[39,389,390,393,396,399],{"class":41,"line":252},[39,391,392],{"class":287},"print",[39,394,395],{"class":227},"(",[39,397,398],{"class":49},"\"all sheets:\"",[39,400,401],{"class":227},", wb.sheetnames)\n",[39,403,404,407,410,413],{"class":41,"line":264},[39,405,406],{"class":223},"for",[39,408,409],{"class":227}," ws ",[39,411,412],{"class":223},"in",[39,414,415],{"class":227}," wb.worksheets:\n",[39,417,418,420,422,424,427,429,432,435,437,440,443,445,447],{"class":41,"line":284},[39,419,288],{"class":287},[39,421,395],{"class":227},[39,423,294],{"class":223},[39,425,426],{"class":49},"\"  ",[39,428,301],{"class":300},[39,430,431],{"class":227},"ws.title",[39,433,434],{"class":223},":8",[39,436,316],{"class":300},[39,438,439],{"class":300}," {",[39,441,442],{"class":227},"ws.sheet_state",[39,444,316],{"class":300},[39,446,297],{"class":49},[39,448,322],{"class":227},[39,450,452],{"class":41,"line":451},7,[39,453,454],{"class":227},"wb.close()\n",[10,456,457,460,461,464,465,468,469,376,472,475,476,479,480,483],{},[14,458,459],{},"wb.sheetnames"," includes chartsheets; ",[14,462,463],{},"wb.worksheets"," only real worksheets. ",[14,466,467],{},"sheet_state"," is ",[14,470,471],{},"visible",[14,473,474],{},"hidden"," or ",[14,477,478],{},"veryHidden"," — the last one cannot be unhidden from Excel's menu, and is a common place for lookup tables that a template does not want users to touch. Hidden sheets are still returned by pandas, so a loop over ",[14,481,482],{},"sheet_names"," reads them too unless you filter on the state.",[25,485,487],{"id":486},"step-2-read-only-the-header-row","Step 2 — Read only the header row",[10,489,490,491,494,495,498,499,502],{},"Pass ",[14,492,493],{},"nrows=0"," and ",[14,496,497],{},"read_excel"," returns an empty DataFrame whose columns are the header row. With ",[14,500,501],{},"sheet_name=None"," it does that for every sheet:",[30,504,506],{"className":214,"code":505,"language":216,"meta":35,"style":35},"t = time.perf_counter()\nheaders = pd.read_excel(\"sales_2025.xlsx\", sheet_name=None, nrows=0)\nfor sheet, frame in headers.items():\n    print(f\"{sheet:8} {list(frame.columns)}\")\nprint(f\"{time.perf_counter() - t:.3f}s\")\n\nt = time.perf_counter()\nfull = pd.read_excel(\"sales_2025.xlsx\", sheet_name=\"Orders\")\nprint(full.shape, f\"full read: {time.perf_counter() - t:.2f}s\")\n",[14,507,508,516,549,561,594,620,624,632,655],{"__ignoreMap":35},[39,509,510,512,514],{"class":41,"line":42},[39,511,255],{"class":227},[39,513,258],{"class":223},[39,515,261],{"class":227},[39,517,518,521,523,526,528,530,533,535,538,540,543,545,547],{"class":41,"line":231},[39,519,520],{"class":227},"headers ",[39,522,258],{"class":223},[39,524,525],{"class":227}," pd.read_excel(",[39,527,273],{"class":49},[39,529,376],{"class":227},[39,531,532],{"class":379},"sheet_name",[39,534,258],{"class":223},[39,536,537],{"class":287},"None",[39,539,376],{"class":227},[39,541,542],{"class":379},"nrows",[39,544,258],{"class":223},[39,546,106],{"class":287},[39,548,322],{"class":227},[39,550,551,553,556,558],{"class":41,"line":245},[39,552,406],{"class":223},[39,554,555],{"class":227}," sheet, frame ",[39,557,412],{"class":223},[39,559,560],{"class":227}," headers.items():\n",[39,562,563,565,567,569,571,573,576,578,580,582,585,588,590,592],{"class":41,"line":252},[39,564,288],{"class":287},[39,566,395],{"class":227},[39,568,294],{"class":223},[39,570,297],{"class":49},[39,572,301],{"class":300},[39,574,575],{"class":227},"sheet",[39,577,434],{"class":223},[39,579,316],{"class":300},[39,581,439],{"class":300},[39,583,584],{"class":287},"list",[39,586,587],{"class":227},"(frame.columns)",[39,589,316],{"class":300},[39,591,297],{"class":49},[39,593,322],{"class":227},[39,595,596,598,600,602,604,606,608,610,612,614,616,618],{"class":41,"line":264},[39,597,392],{"class":287},[39,599,395],{"class":227},[39,601,294],{"class":223},[39,603,297],{"class":49},[39,605,301],{"class":300},[39,607,304],{"class":227},[39,609,307],{"class":223},[39,611,310],{"class":227},[39,613,313],{"class":223},[39,615,316],{"class":300},[39,617,319],{"class":49},[39,619,322],{"class":227},[39,621,622],{"class":41,"line":284},[39,623,249],{"emptyLinePlaceholder":248},[39,625,626,628,630],{"class":41,"line":451},[39,627,255],{"class":227},[39,629,258],{"class":223},[39,631,261],{"class":227},[39,633,635,638,640,642,644,646,648,650,653],{"class":41,"line":634},8,[39,636,637],{"class":227},"full ",[39,639,258],{"class":223},[39,641,525],{"class":227},[39,643,273],{"class":49},[39,645,376],{"class":227},[39,647,532],{"class":379},[39,649,258],{"class":223},[39,651,652],{"class":49},"\"Orders\"",[39,654,322],{"class":227},[39,656,658,660,663,665,668,670,672,674,676,679,681,683],{"class":41,"line":657},9,[39,659,392],{"class":287},[39,661,662],{"class":227},"(full.shape, ",[39,664,294],{"class":223},[39,666,667],{"class":49},"\"full read: ",[39,669,301],{"class":300},[39,671,304],{"class":227},[39,673,307],{"class":223},[39,675,310],{"class":227},[39,677,678],{"class":223},":.2f",[39,680,316],{"class":300},[39,682,319],{"class":49},[39,684,322],{"class":227},[10,686,687,688,691,692,694],{},"pandas reads ",[14,689,690],{},".xlsx"," files through openpyxl in read-only mode, which parses the sheet XML as a stream and stops after the rows it needs, so the cost of ",[14,693,493],{}," does not depend on how big the sheet is. Here it takes milliseconds, while the full read of the 200,000-row sheet takes a few seconds — the exact numbers depend on the machine, but the gap is typically three orders of magnitude.",[84,696,93,702,93,705,93,708,93,713,93,722,93,728,93,733,93,738,93,741,93,745,93,747,93,750,93,753,93,757,93,759,93,761,93,764,93,768,93,771,93,776],{"viewBox":697,"role":87,"ariaLabelledBy":698,"xmlns":91,"style":701},"4 0 744 206",[699,700],"sh-times-t","sh-times-d","width:100%;max-width:744px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[95,703,704],{"id":699},"Time to answer each question on a 200,000-row workbook",[99,706,707],{"id":700},"Bar chart of measured times. Listing sheet names, reading the header row and reading the used range all take about 3 to 4 milliseconds; reading the whole sheet takes about 3,700 milliseconds.",[103,709],{"x":710,"y":106,"width":711,"height":712,"fill":109},"4","744","206",[103,714],{"x":715,"y":113,"width":716,"height":717,"rx":718,"fill":719,"stroke":720,"style":721},"20.0","171.5","28.0","7","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[132,723,727],{"x":724,"y":725,"style":726},"105.8","34.5","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","sheet names",[103,729],{"x":730,"y":113,"width":731,"height":717,"rx":718,"fill":117,"stroke":118,"style":732},"201.5","6.0","stroke-width:1.5px",[132,734,737],{"x":735,"y":725,"style":736},"215.5","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","3 ms",[103,739],{"x":715,"y":740,"width":716,"height":717,"rx":718,"fill":719,"stroke":720,"style":721},"56.0",[132,742,744],{"x":724,"y":743,"style":726},"74.5","header row (nrows=0)",[103,746],{"x":730,"y":740,"width":731,"height":717,"rx":718,"fill":117,"stroke":118,"style":732},[132,748,749],{"x":735,"y":743,"style":736},"4 ms",[103,751],{"x":715,"y":752,"width":716,"height":717,"rx":718,"fill":719,"stroke":720,"style":721},"96.0",[132,754,756],{"x":724,"y":755,"style":726},"114.5","used range",[103,758],{"x":730,"y":752,"width":731,"height":717,"rx":718,"fill":117,"stroke":118,"style":732},[132,760,737],{"x":735,"y":755,"style":736},[103,762],{"x":715,"y":763,"width":716,"height":717,"rx":718,"fill":719,"stroke":720,"style":721},"136.0",[132,765,767],{"x":724,"y":766,"style":726},"154.5","full read_excel",[103,769],{"x":730,"y":763,"width":770,"height":717,"rx":718,"fill":184,"stroke":185,"style":732},"463.7",[132,772,775],{"x":773,"y":766,"style":774},"673.2","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","3,664 ms",[132,777,780],{"x":134,"y":778,"style":779},"186.0","font-size:12.5px;font-weight:400;fill:var(--muted,#5b6780);text-anchor:middle","Measured with pandas 3.0 and openpyxl 3.1 on a 7 MB file; your timings will differ, the ratio will not.",[10,782,783,784,786,787,790,791,795],{},"If the header is not in the first row — a report with a title and a blank line above the table — ",[14,785,493],{}," returns the title as column names. Read the first few rows with ",[14,788,789],{},"header=None, nrows=10"," instead and look for the header, as described in ",[19,792,794],{"href":793},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Ffind-the-header-row-in-an-excel-sheet-with-a-shifting-layout\u002F","Find the Header Row in an Excel Sheet with a Shifting Layout",".",[25,797,799],{"id":798},"step-3-get-the-size-of-each-sheet","Step 3 — Get the size of each sheet",[10,801,802,803,806,807,810],{},"Most writers — Excel, openpyxl, xlsxwriter — store a ",[14,804,805],{},"\u003Cdimension>"," record at the top of each sheet with the used range, such as ",[14,808,809],{},"A1:E200001",". In read-only mode openpyxl reads it without loading the rows:",[30,812,814],{"className":214,"code":813,"language":216,"meta":35,"style":35},"wb = load_workbook(\"sales_2025.xlsx\", read_only=True)\nfor ws in wb.worksheets:\n    print(f\"{ws.title:8} {ws.calculate_dimension():12} rows={ws.max_row:>7} cols={ws.max_column}\")\nwb.close()\n",[14,815,816,836,846,901],{"__ignoreMap":35},[39,817,818,820,822,824,826,828,830,832,834],{"class":41,"line":42},[39,819,366],{"class":227},[39,821,258],{"class":223},[39,823,371],{"class":227},[39,825,273],{"class":49},[39,827,376],{"class":227},[39,829,380],{"class":379},[39,831,258],{"class":223},[39,833,385],{"class":287},[39,835,322],{"class":227},[39,837,838,840,842,844],{"class":41,"line":231},[39,839,406],{"class":223},[39,841,409],{"class":227},[39,843,412],{"class":223},[39,845,415],{"class":227},[39,847,848,850,852,854,856,858,860,862,864,866,869,872,874,877,879,882,885,887,890,892,895,897,899],{"class":41,"line":245},[39,849,288],{"class":287},[39,851,395],{"class":227},[39,853,294],{"class":223},[39,855,297],{"class":49},[39,857,301],{"class":300},[39,859,431],{"class":227},[39,861,434],{"class":223},[39,863,316],{"class":300},[39,865,439],{"class":300},[39,867,868],{"class":227},"ws.calculate_dimension()",[39,870,871],{"class":223},":12",[39,873,316],{"class":300},[39,875,876],{"class":49}," rows=",[39,878,301],{"class":300},[39,880,881],{"class":227},"ws.max_row",[39,883,884],{"class":223},":>7",[39,886,316],{"class":300},[39,888,889],{"class":49}," cols=",[39,891,301],{"class":300},[39,893,894],{"class":227},"ws.max_column",[39,896,316],{"class":300},[39,898,297],{"class":49},[39,900,322],{"class":227},[39,902,903],{"class":41,"line":252},[39,904,454],{"class":227},[10,906,907,908,468,911,494,913,916,917,920,921,924,925,929],{},"The dimension is written by whatever program saved the file, so treat it as a hint. Some exporters leave it out; then ",[14,909,910],{},"max_row",[14,912,537],{},[14,914,915],{},"calculate_dimension()"," raises ",[14,918,919],{},"ValueError: Worksheet is unsized",". ",[14,922,923],{},"calculate_dimension(force=True)"," scans the sheet to find out, which costs a full pass. Formatted but empty rows at the bottom also count as used — ",[19,926,928],{"href":927},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fcount-rows-in-an-excel-file-without-loading-it\u002F","Count Rows in an Excel File Without Loading It"," covers exact counts.",[25,931,933],{"id":932},"step-4-catalogue-a-folder-of-workbooks","Step 4 — Catalogue a folder of workbooks",[10,935,936],{},"The same calls, looped over a folder, produce an inventory of every file, sheet and column — the quickest way to spot the one export whose columns do not match the rest before a combining script fails on it:",[30,938,940],{"className":214,"code":939,"language":216,"meta":35,"style":35},"from pathlib import Path\n\nrows = []\nfor path in sorted(Path(\"exports\").glob(\"*.xlsx\")):\n    wb = load_workbook(path, read_only=True)\n    for ws in wb.worksheets:\n        header = next(ws.iter_rows(max_row=1, values_only=True), ())\n        rows.append({\"File\": path.name, \"Sheet\": ws.title, \"State\": ws.sheet_state,\n                     \"Range\": ws.calculate_dimension(), \"Columns\": \", \".join(map(str, header))})\n    wb.close()\n\ncatalogue = pd.DataFrame(rows)\nprint(catalogue.to_string(index=False))\n\nexpected = catalogue[\"Columns\"].mode()[0]\nprint(\"\\nodd one out:\", catalogue.loc[catalogue[\"Columns\"] != expected, [\"File\", \"Columns\"]].values.tolist())\ncatalogue.to_excel(\"catalogue.xlsx\", index=False)\n",[14,941,942,954,958,968,995,1013,1024,1056,1079,1110,1116,1121,1132,1151,1156,1177,1215],{"__ignoreMap":35},[39,943,944,946,949,951],{"class":41,"line":42},[39,945,349],{"class":223},[39,947,948],{"class":227}," pathlib ",[39,950,224],{"class":223},[39,952,953],{"class":227}," Path\n",[39,955,956],{"class":41,"line":231},[39,957,249],{"emptyLinePlaceholder":248},[39,959,960,963,965],{"class":41,"line":245},[39,961,962],{"class":227},"rows ",[39,964,258],{"class":223},[39,966,967],{"class":227}," []\n",[39,969,970,972,975,977,980,983,986,989,992],{"class":41,"line":252},[39,971,406],{"class":223},[39,973,974],{"class":227}," path ",[39,976,412],{"class":223},[39,978,979],{"class":287}," sorted",[39,981,982],{"class":227},"(Path(",[39,984,985],{"class":49},"\"exports\"",[39,987,988],{"class":227},").glob(",[39,990,991],{"class":49},"\"*.xlsx\"",[39,993,994],{"class":227},")):\n",[39,996,997,1000,1002,1005,1007,1009,1011],{"class":41,"line":264},[39,998,999],{"class":227},"    wb ",[39,1001,258],{"class":223},[39,1003,1004],{"class":227}," load_workbook(path, ",[39,1006,380],{"class":379},[39,1008,258],{"class":223},[39,1010,385],{"class":287},[39,1012,322],{"class":227},[39,1014,1015,1018,1020,1022],{"class":41,"line":284},[39,1016,1017],{"class":223},"    for",[39,1019,409],{"class":227},[39,1021,412],{"class":223},[39,1023,415],{"class":227},[39,1025,1026,1029,1031,1034,1037,1039,1041,1044,1046,1049,1051,1053],{"class":41,"line":451},[39,1027,1028],{"class":227},"        header ",[39,1030,258],{"class":223},[39,1032,1033],{"class":287}," next",[39,1035,1036],{"class":227},"(ws.iter_rows(",[39,1038,910],{"class":379},[39,1040,258],{"class":223},[39,1042,1043],{"class":287},"1",[39,1045,376],{"class":227},[39,1047,1048],{"class":379},"values_only",[39,1050,258],{"class":223},[39,1052,385],{"class":287},[39,1054,1055],{"class":227},"), ())\n",[39,1057,1058,1061,1064,1067,1070,1073,1076],{"class":41,"line":634},[39,1059,1060],{"class":227},"        rows.append({",[39,1062,1063],{"class":49},"\"File\"",[39,1065,1066],{"class":227},": path.name, ",[39,1068,1069],{"class":49},"\"Sheet\"",[39,1071,1072],{"class":227},": ws.title, ",[39,1074,1075],{"class":49},"\"State\"",[39,1077,1078],{"class":227},": ws.sheet_state,\n",[39,1080,1081,1084,1087,1090,1093,1096,1099,1102,1104,1107],{"class":41,"line":657},[39,1082,1083],{"class":49},"                     \"Range\"",[39,1085,1086],{"class":227},": ws.calculate_dimension(), ",[39,1088,1089],{"class":49},"\"Columns\"",[39,1091,1092],{"class":227},": ",[39,1094,1095],{"class":49},"\", \"",[39,1097,1098],{"class":227},".join(",[39,1100,1101],{"class":287},"map",[39,1103,395],{"class":227},[39,1105,1106],{"class":287},"str",[39,1108,1109],{"class":227},", header))})\n",[39,1111,1113],{"class":41,"line":1112},10,[39,1114,1115],{"class":227},"    wb.close()\n",[39,1117,1119],{"class":41,"line":1118},11,[39,1120,249],{"emptyLinePlaceholder":248},[39,1122,1124,1127,1129],{"class":41,"line":1123},12,[39,1125,1126],{"class":227},"catalogue ",[39,1128,258],{"class":223},[39,1130,1131],{"class":227}," pd.DataFrame(rows)\n",[39,1133,1135,1137,1140,1143,1145,1148],{"class":41,"line":1134},13,[39,1136,392],{"class":287},[39,1138,1139],{"class":227},"(catalogue.to_string(",[39,1141,1142],{"class":379},"index",[39,1144,258],{"class":223},[39,1146,1147],{"class":287},"False",[39,1149,1150],{"class":227},"))\n",[39,1152,1154],{"class":41,"line":1153},14,[39,1155,249],{"emptyLinePlaceholder":248},[39,1157,1159,1162,1164,1167,1169,1172,1174],{"class":41,"line":1158},15,[39,1160,1161],{"class":227},"expected ",[39,1163,258],{"class":223},[39,1165,1166],{"class":227}," catalogue[",[39,1168,1089],{"class":49},[39,1170,1171],{"class":227},"].mode()[",[39,1173,106],{"class":287},[39,1175,1176],{"class":227},"]\n",[39,1178,1180,1182,1184,1186,1189,1192,1195,1197,1200,1203,1206,1208,1210,1212],{"class":41,"line":1179},16,[39,1181,392],{"class":287},[39,1183,395],{"class":227},[39,1185,297],{"class":49},[39,1187,1188],{"class":300},"\\n",[39,1190,1191],{"class":49},"odd one out:\"",[39,1193,1194],{"class":227},", catalogue.loc[catalogue[",[39,1196,1089],{"class":49},[39,1198,1199],{"class":227},"] ",[39,1201,1202],{"class":223},"!=",[39,1204,1205],{"class":227}," expected, [",[39,1207,1063],{"class":49},[39,1209,376],{"class":227},[39,1211,1089],{"class":49},[39,1213,1214],{"class":227},"]].values.tolist())\n",[39,1216,1218,1221,1224,1226,1228,1230,1232],{"class":41,"line":1217},17,[39,1219,1220],{"class":227},"catalogue.to_excel(",[39,1222,1223],{"class":49},"\"catalogue.xlsx\"",[39,1225,376],{"class":227},[39,1227,1142],{"class":379},[39,1229,258],{"class":223},[39,1231,1147],{"class":287},[39,1233,322],{"class":227},[10,1235,1236,1239,1240,1243,1244,1247,1248,1251,1252,920,1255,1259],{},[14,1237,1238],{},"iter_rows(max_row=1, values_only=True)"," yields just the first row as a tuple of values; ",[14,1241,1242],{},"next(..., ())"," handles an empty sheet. Comparing each file's header with the most common one flags ",[14,1245,1246],{},"stores_east.xlsx",", where ",[14,1249,1250],{},"Sales"," was renamed to ",[14,1253,1254],{},"Revenue",[19,1256,1258],{"href":1257},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fmerge-excel-files-with-different-column-names\u002F","Merge Excel Files with Different Column Names"," shows how to map it back before combining.",[84,1261,93,1267,93,1270,93,1273,93,1278,93,1284,93,1289,93,1296,93,1302,93,1307,93,1310,93,1316,93,1320,93,1324,93,1328,93,1331,93,1335,93,1339,93,1343,93,1347,93,1350,93,1354,93,1356,93,1360,93,1362,93,1365,93,1367,93,1370,93,1372,93,1375,93,1377,93,1380,93,1383,93,1387,93,1389,93,1392,93,1394,93,1397,93,1399,93,1401,93,1403,93,1406,93,1410,93,1414,93,1417,93,1421,93,1423,93,1426,93,1428,93,1430,93,1432,93,1434,93,1436,93,1439,93,1441,93,1444,93,1447,93,1450,93,1452,93,1455,93,1457,93,1459,93,1461,93,1463,93,1465,93,1468,93,1470],{"viewBox":1262,"role":87,"ariaLabelledBy":1263,"xmlns":91,"style":1266},"106 0 547 198",[1264,1265],"sh-catalogue-t","sh-catalogue-d","width:100%;max-width:547px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[95,1268,1269],{"id":1264},"The catalogue written to catalogue.xlsx",[99,1271,1272],{"id":1265},"A worksheet listing each file, its sheet, state, used range and columns. The east file's columns row is highlighted because it has Revenue instead of Sales.",[103,1274],{"x":1275,"y":106,"width":1276,"height":1277,"fill":109},"106","547","198",[103,1279],{"x":1280,"y":113,"width":1281,"height":1282,"rx":1283,"fill":719,"stroke":720,"style":732},"122.6","514.8","30.0","8",[103,1285],{"x":1280,"y":1286,"width":1281,"height":1287,"rx":106,"fill":719,"stroke":720,"style":1288},"38.0","8.0","stroke-width:0px",[121,1290,1292],{"transform":1291},"translate(132.6,23.0) scale(0.667)",[125,1293],{"d":1294,"fill":128,"stroke":129,"style":1295},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6","stroke-width:2.70px;stroke-linecap:round;stroke-linejoin:round",[132,1297,1301],{"x":1298,"y":1299,"style":1300},"154.6","36.0","font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:start","catalogue.xlsx",[103,1303],{"x":1280,"y":1304,"width":1305,"height":1306,"rx":106,"fill":719,"stroke":720,"style":721},"46.0","32.0","24.0",[103,1308],{"x":1298,"y":1304,"width":1309,"height":1306,"rx":106,"fill":719,"stroke":720,"style":721},"133.5",[132,1311,1315],{"x":1312,"y":1313,"style":1314},"221.3","63.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[103,1317],{"x":1318,"y":1304,"width":1319,"height":1306,"rx":106,"fill":719,"stroke":720,"style":721},"288.1","59.7",[132,1321,1323],{"x":1322,"y":1313,"style":1314},"317.9","B",[103,1325],{"x":1326,"y":1304,"width":1327,"height":1306,"rx":106,"fill":719,"stroke":720,"style":721},"347.8","64.3",[132,1329,1330],{"x":134,"y":1313,"style":1314},"C",[103,1332],{"x":1333,"y":1304,"width":1334,"height":1306,"rx":106,"fill":719,"stroke":720,"style":721},"412.1","69.4",[132,1336,1338],{"x":1337,"y":1313,"style":1314},"446.8","D",[103,1340],{"x":1341,"y":1304,"width":1342,"height":1306,"rx":106,"fill":719,"stroke":720,"style":721},"481.5","155.9",[132,1344,1346],{"x":1345,"y":1313,"style":1314},"559.4","E",[103,1348],{"x":1280,"y":1349,"width":1305,"height":717,"rx":106,"fill":719,"stroke":720,"style":721},"70.0",[132,1351,1043],{"x":1352,"y":1353,"style":1314},"138.6","89.0",[103,1355],{"x":1298,"y":1349,"width":1309,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1357,1359],{"x":1312,"y":1353,"style":1358},"font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","File",[103,1361],{"x":1318,"y":1349,"width":1319,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1363,1364],{"x":1322,"y":1353,"style":1358},"Sheet",[103,1366],{"x":1326,"y":1349,"width":1327,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1368,1369],{"x":134,"y":1353,"style":1358},"State",[103,1371],{"x":1333,"y":1349,"width":1334,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1373,1374],{"x":1337,"y":1353,"style":1358},"Range",[103,1376],{"x":1341,"y":1349,"width":1342,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1378,1379],{"x":1345,"y":1353,"style":1358},"Columns",[103,1381],{"x":1280,"y":1382,"width":1305,"height":717,"rx":106,"fill":719,"stroke":720,"style":721},"98.0",[132,1384,1386],{"x":1352,"y":1385,"style":1314},"117.0","2",[103,1388],{"x":1298,"y":1382,"width":1309,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1390,1246],{"x":1312,"y":1385,"style":1391},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[103,1393],{"x":1318,"y":1382,"width":1319,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1395,1396],{"x":1322,"y":1385,"style":1391},"Data",[103,1398],{"x":1326,"y":1382,"width":1327,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1400,471],{"x":134,"y":1385,"style":1391},[103,1402],{"x":1333,"y":1382,"width":1334,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1404,1405],{"x":1337,"y":1385,"style":1391},"A1:C90",[103,1407],{"x":1341,"y":1382,"width":1342,"height":717,"rx":106,"fill":1408,"stroke":1409,"style":732},"#fce9e9","var(--danger,#dc2626)",[132,1411,1413],{"x":1345,"y":1385,"style":1412},"font-size:12px;font-weight:700;fill:var(--accent-ink,#be185d);text-anchor:middle","Store, Revenue, Staff",[103,1415],{"x":1280,"y":1416,"width":1305,"height":717,"rx":106,"fill":719,"stroke":720,"style":721},"126.0",[132,1418,1420],{"x":1352,"y":1419,"style":1314},"145.0","3",[103,1422],{"x":1298,"y":1416,"width":1309,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1424,1425],{"x":1312,"y":1419,"style":1391},"stores_north.xlsx",[103,1427],{"x":1318,"y":1416,"width":1319,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1429,1396],{"x":1322,"y":1419,"style":1391},[103,1431],{"x":1326,"y":1416,"width":1327,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1433,471],{"x":134,"y":1419,"style":1391},[103,1435],{"x":1333,"y":1416,"width":1334,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1437,1438],{"x":1337,"y":1419,"style":1391},"A1:C40",[103,1440],{"x":1341,"y":1416,"width":1342,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1442,1443],{"x":1345,"y":1419,"style":1391},"Store, Sales, Staff",[103,1445],{"x":1280,"y":1446,"width":1305,"height":717,"rx":106,"fill":719,"stroke":720,"style":721},"154.0",[132,1448,710],{"x":1352,"y":1449,"style":1314},"173.0",[103,1451],{"x":1298,"y":1446,"width":1309,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1453,1454],{"x":1312,"y":1449,"style":1391},"stores_south.xlsx",[103,1456],{"x":1318,"y":1446,"width":1319,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1458,1396],{"x":1322,"y":1449,"style":1391},[103,1460],{"x":1326,"y":1446,"width":1327,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1462,471],{"x":134,"y":1449,"style":1391},[103,1464],{"x":1333,"y":1446,"width":1334,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1466,1467],{"x":1337,"y":1449,"style":1391},"A1:C65",[103,1469],{"x":1341,"y":1446,"width":1342,"height":717,"rx":106,"fill":109,"stroke":720,"style":721},[132,1471,1443],{"x":1345,"y":1449,"style":1391},[25,1473,1475],{"id":1474},"step-5-choose-the-sheet-to-read-by-its-columns","Step 5 — Choose the sheet to read by its columns",[10,1477,1478,1479,376,1481,376,1484,376,1487,1490],{},"Sheet names are the least reliable part of a workbook people maintain by hand: ",[14,1480,1396],{},[14,1482,1483],{},"data (2)",[14,1485,1486],{},"Export_Final",[14,1488,1489],{},"Sheet1",". The header row is usually steadier. When the job needs \"the sheet with an order ID, a date and an amount\", look for those columns in the headers you already have and read only that sheet:",[30,1492,1494],{"className":214,"code":1493,"language":216,"meta":35,"style":35},"REQUIRED = {\"OrderID\", \"Date\", \"Amount\"}\n\ndef find_sheet(path, required):\n    headers = pd.read_excel(path, sheet_name=None, nrows=0)\n    matches = [name for name, frame in headers.items() if required \u003C= set(frame.columns)]\n    if len(matches) != 1:\n        raise ValueError(f\"{path}: expected one sheet with {sorted(required)}, found {matches}\")\n    return matches[0]\n\nsheet = find_sheet(\"sales_2025.xlsx\", REQUIRED)\norders = pd.read_excel(\"sales_2025.xlsx\", sheet_name=sheet, usecols=list(REQUIRED) + [\"Region\"])\nprint(sheet, orders.shape, list(orders.columns))\n",[14,1495,1496,1522,1526,1538,1564,1599,1618,1665,1677,1681,1699,1744],{"__ignoreMap":35},[39,1497,1498,1501,1504,1506,1509,1511,1514,1516,1519],{"class":41,"line":42},[39,1499,1500],{"class":287},"REQUIRED",[39,1502,1503],{"class":223}," =",[39,1505,439],{"class":227},[39,1507,1508],{"class":49},"\"OrderID\"",[39,1510,376],{"class":227},[39,1512,1513],{"class":49},"\"Date\"",[39,1515,376],{"class":227},[39,1517,1518],{"class":49},"\"Amount\"",[39,1520,1521],{"class":227},"}\n",[39,1523,1524],{"class":41,"line":231},[39,1525,249],{"emptyLinePlaceholder":248},[39,1527,1528,1531,1535],{"class":41,"line":245},[39,1529,1530],{"class":223},"def",[39,1532,1534],{"class":1533},"s_Opv"," find_sheet",[39,1536,1537],{"class":227},"(path, required):\n",[39,1539,1540,1543,1545,1548,1550,1552,1554,1556,1558,1560,1562],{"class":41,"line":252},[39,1541,1542],{"class":227},"    headers ",[39,1544,258],{"class":223},[39,1546,1547],{"class":227}," pd.read_excel(path, ",[39,1549,532],{"class":379},[39,1551,258],{"class":223},[39,1553,537],{"class":287},[39,1555,376],{"class":227},[39,1557,542],{"class":379},[39,1559,258],{"class":223},[39,1561,106],{"class":287},[39,1563,322],{"class":227},[39,1565,1566,1569,1571,1574,1576,1579,1581,1584,1587,1590,1593,1596],{"class":41,"line":264},[39,1567,1568],{"class":227},"    matches ",[39,1570,258],{"class":223},[39,1572,1573],{"class":227}," [name ",[39,1575,406],{"class":223},[39,1577,1578],{"class":227}," name, frame ",[39,1580,412],{"class":223},[39,1582,1583],{"class":227}," headers.items() ",[39,1585,1586],{"class":223},"if",[39,1588,1589],{"class":227}," required ",[39,1591,1592],{"class":223},"\u003C=",[39,1594,1595],{"class":287}," set",[39,1597,1598],{"class":227},"(frame.columns)]\n",[39,1600,1601,1604,1607,1610,1612,1615],{"class":41,"line":284},[39,1602,1603],{"class":223},"    if",[39,1605,1606],{"class":287}," len",[39,1608,1609],{"class":227},"(matches) ",[39,1611,1202],{"class":223},[39,1613,1614],{"class":287}," 1",[39,1616,1617],{"class":227},":\n",[39,1619,1620,1623,1626,1628,1630,1632,1634,1636,1638,1641,1643,1646,1649,1651,1654,1656,1659,1661,1663],{"class":41,"line":451},[39,1621,1622],{"class":223},"        raise",[39,1624,1625],{"class":287}," ValueError",[39,1627,395],{"class":227},[39,1629,294],{"class":223},[39,1631,297],{"class":49},[39,1633,301],{"class":300},[39,1635,125],{"class":227},[39,1637,316],{"class":300},[39,1639,1640],{"class":49},": expected one sheet with ",[39,1642,301],{"class":300},[39,1644,1645],{"class":287},"sorted",[39,1647,1648],{"class":227},"(required)",[39,1650,316],{"class":300},[39,1652,1653],{"class":49},", found ",[39,1655,301],{"class":300},[39,1657,1658],{"class":227},"matches",[39,1660,316],{"class":300},[39,1662,297],{"class":49},[39,1664,322],{"class":227},[39,1666,1667,1670,1673,1675],{"class":41,"line":634},[39,1668,1669],{"class":223},"    return",[39,1671,1672],{"class":227}," matches[",[39,1674,106],{"class":287},[39,1676,1176],{"class":227},[39,1678,1679],{"class":41,"line":657},[39,1680,249],{"emptyLinePlaceholder":248},[39,1682,1683,1686,1688,1691,1693,1695,1697],{"class":41,"line":1112},[39,1684,1685],{"class":227},"sheet ",[39,1687,258],{"class":223},[39,1689,1690],{"class":227}," find_sheet(",[39,1692,273],{"class":49},[39,1694,376],{"class":227},[39,1696,1500],{"class":287},[39,1698,322],{"class":227},[39,1700,1701,1704,1706,1708,1710,1712,1714,1716,1719,1722,1724,1726,1728,1730,1732,1735,1738,1741],{"class":41,"line":1118},[39,1702,1703],{"class":227},"orders ",[39,1705,258],{"class":223},[39,1707,525],{"class":227},[39,1709,273],{"class":49},[39,1711,376],{"class":227},[39,1713,532],{"class":379},[39,1715,258],{"class":223},[39,1717,1718],{"class":227},"sheet, ",[39,1720,1721],{"class":379},"usecols",[39,1723,258],{"class":223},[39,1725,584],{"class":287},[39,1727,395],{"class":227},[39,1729,1500],{"class":287},[39,1731,276],{"class":227},[39,1733,1734],{"class":223},"+",[39,1736,1737],{"class":227}," [",[39,1739,1740],{"class":49},"\"Region\"",[39,1742,1743],{"class":227},"])\n",[39,1745,1746,1748,1751,1753],{"class":41,"line":1123},[39,1747,392],{"class":287},[39,1749,1750],{"class":227},"(sheet, orders.shape, ",[39,1752,584],{"class":287},[39,1754,1755],{"class":227},"(orders.columns))\n",[10,1757,1758,1761,1762,1764],{},[14,1759,1760],{},"required \u003C= set(columns)"," is a subset test: every required column must be present, extra columns are fine. Raising when zero or several sheets match is deliberate — a workbook where two sheets both look like the order list needs a person to decide, and guessing would silently read the wrong one. Passing ",[14,1763,1721],{}," with the columns the job needs also makes the one full read cheaper, because pandas skips converting the other columns.",[10,1766,1767,1768,1771,1772,1776],{},"The same check doubles as input validation for scheduled jobs: run it first, and a file that arrives with renamed columns fails with a message naming the file and the columns it expected, rather than a ",[14,1769,1770],{},"KeyError"," twenty lines later. ",[19,1773,1775],{"href":1774},"\u002Fadvanced-data-transformation-and-cleaning\u002Fvalidating-excel-data-with-python\u002Fvalidate-excel-columns-before-import-with-pandas\u002F","Validate Excel Columns Before Import with pandas"," takes the idea further, with types and allowed values.",[25,1778,1780],{"id":1779},"common-pitfalls","Common pitfalls",[1782,1783,1784,1799,1816,1827,1837],"ul",{},[1785,1786,1787,1795,1796,795],"li",{},[1788,1789,1790,1791,1794],"strong",{},"Calling ",[14,1792,1793],{},"read_excel(sheet_name=None)"," to get names."," It reads every sheet in full. Use ",[14,1797,1798],{},"pd.ExcelFile(path).sheet_names",[1785,1800,1801,1804,1805,1808,1809,1812,1813,1815],{},[1788,1802,1803],{},"Forgetting to close files."," Read-only workbooks keep the file handle open until ",[14,1806,1807],{},"wb.close()",", and a bare ",[14,1810,1811],{},"pd.ExcelFile(path)"," stays open until it is garbage-collected; on Windows the file stays locked and a later write fails with a permission error. Use ",[14,1814,267],{}," blocks or close explicitly.",[1785,1817,1818,1821,1822,1826],{},[1788,1819,1820],{},"Trusting the dimension."," It can be missing, or cover formatted empty rows. Use it to decide ",[1823,1824,1825],"em",{},"how"," to read a file, not as a row count for validation.",[1785,1828,1829,1832,1833,1836],{},[1788,1830,1831],{},"Chartsheets and pandas."," ",[14,1834,1835],{},"sheet_name=2"," counts worksheets only, so positions differ from the tab order in Excel when a chartsheet sits between them. Refer to sheets by name.",[1785,1838,1839,1832,1846,1849,1850,1852,1853,1855,1856,795],{},[1788,1840,1841,1842,1845],{},"Old ",[14,1843,1844],{},".xls"," files.",[14,1847,1848],{},"load_workbook"," does not open ",[14,1851,1844],{},"; ",[14,1854,210],{}," does, through xlrd, and still lists the sheets cheaply. See ",[19,1857,1859],{"href":1858},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fread-xls-files-in-python-with-xlrd-and-pandas\u002F","Read .xls Files in Python",[25,1861,1863],{"id":1862},"performance-notes","Performance notes",[10,1865,1866,1867,1870],{},"Every call on this page reads a fixed, small part of the file, so the time per file is roughly constant — a few milliseconds plus the cost of opening the zip. A catalogue of a thousand workbooks takes seconds. The one exception is a sheet without a dimension record, where finding the size needs a full scan; skip ",[14,1868,1869],{},"calculate_dimension"," for those unless you need the number.",[25,1872,1874],{"id":1873},"conclusion","Conclusion",[10,1876,1877,1878,1880,1881,1884],{},"Ask the workbook for its metadata before reading its data. ",[14,1879,1798],{}," lists the worksheets, ",[14,1882,1883],{},"read_excel(..., nrows=0)"," returns just the header row of one or all sheets, and openpyxl's read-only mode adds hidden and chartsheet information plus the used range from each sheet's dimension record. Loop those calls over a folder to catalogue every file and catch the mismatched export before it breaks the job that combines them.",[25,1886,1888],{"id":1887},"frequently-asked-questions","Frequently asked questions",[10,1890,1891,1894,1895,1898],{},[1788,1892,1893],{},"How do I get the sheet names of an Excel file in pandas?","\nUse ",[14,1896,1897],{},"pd.ExcelFile(\"file.xlsx\").sheet_names",", ideally inside a with block. It reads only the workbook's list of sheets, not their data. pd.read_excel(file, sheet_name=None) also gives the names as dictionary keys, but it reads every sheet in full to do so.",[10,1900,1901,1904],{},[1788,1902,1903],{},"How do I read only the column headers of an Excel sheet?","\nCall pd.read_excel(file, sheet_name=\"Sheet1\", nrows=0). It returns an empty DataFrame whose columns are the header row, and it stops reading after the first row, so it is fast even on very large sheets.",[10,1906,1907,1910],{},[1788,1908,1909],{},"Why is my chartsheet missing from pandas' sheet_names?","\npandas lists only worksheets, because a chartsheet has no cells. openpyxl's wb.sheetnames lists every sheet, including chartsheets, in tab order.",[10,1912,1913,1916],{},[1788,1914,1915],{},"How can I tell whether a sheet is hidden?","\nOpen the workbook with openpyxl and check ws.sheet_state, which is visible, hidden or veryHidden. pandas does not report visibility and reads hidden sheets like any other.",[25,1918,1920],{"id":1919},"related","Related",[1782,1922,1923,1929,1936,1943],{},[1785,1924,1925,1926,1928],{},"Up one level: ",[19,1927,22],{"href":21}," — the read_excel options that follow the inspection step.",[1785,1930,1931,1935],{},[19,1932,1934],{"href":1933},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-excel-sheets-whose-names-change-with-pandas\u002F","Read Excel Sheets Whose Names Change with pandas"," — picking a sheet from the list by pattern.",[1785,1937,1938,1942],{},[19,1939,1941],{"href":1940},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-multiple-excel-sheets-in-python\u002Fread-all-sheets-from-an-excel-file-into-dataframes\u002F","Read All Sheets from an Excel File into DataFrames"," — when you do want every sheet.",[1785,1944,1945,1949],{},[19,1946,1948],{"href":1947},"\u002Fadvanced-data-transformation-and-cleaning\u002Fworking-with-large-excel-files-in-python\u002Fspeed-up-openpyxl-with-read-only-mode\u002F","Speed Up openpyxl with Read-Only Mode"," — the streaming reader behind these calls.",[1951,1952,1953],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}",{"title":35,"searchDepth":231,"depth":231,"links":1955},[1956,1957,1958,1959,1960,1961,1962,1963,1964,1965,1966],{"id":27,"depth":231,"text":28},{"id":204,"depth":231,"text":205},{"id":486,"depth":231,"text":487},{"id":798,"depth":231,"text":799},{"id":932,"depth":231,"text":933},{"id":1474,"depth":231,"text":1475},{"id":1779,"depth":231,"text":1780},{"id":1862,"depth":231,"text":1863},{"id":1873,"depth":231,"text":1874},{"id":1887,"depth":231,"text":1888},{"id":1919,"depth":231,"text":1920},"2026-09-29","Find out what a workbook contains before reading it: sheet names with pandas and openpyxl, the header row of every sheet with nrows=0, hidden sheets and chartsheets, the used range of each sheet, and a catalogue of a whole folder of files — in milliseconds, not seconds.","md",[1971,1973,1975,1977],{"q":1893,"a":1972},"Use pd.ExcelFile(\"file.xlsx\").sheet_names, ideally inside a with block. It reads only the workbook's list of sheets, not their data. pd.read_excel(file, sheet_name=None) also gives the names as dictionary keys, but it reads every sheet in full to do so.",{"q":1903,"a":1974},"Call pd.read_excel(file, sheet_name=\"Sheet1\", nrows=0). It returns an empty DataFrame whose columns are the header row, and it stops reading after the first row, so it is fast even on very large sheets.",{"q":1909,"a":1976},"pandas lists only worksheets, because a chartsheet has no cells. openpyxl's wb.sheetnames lists every sheet, including chartsheets, in tab order.",{"q":1915,"a":1978},"Open the workbook with openpyxl and check ws.sheet_state, which is visible, hidden or veryHidden. pandas does not report visibility and reads hidden sheets like any other.","list sheet names and column headers without loading data",null,{"breadcrumb":1982},[1983,1986,1989],{"name":1984,"item":1985},"Home","\u002F",{"name":1987,"item":1988},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":1990,"item":21},"Reading Excel Files with Pandas","\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Flist-sheet-names-and-column-headers-without-loading-data",{"title":1993,"description":1994},"Get Excel Sheet Names and Headers in Python Without Loading","List sheet names with pd.ExcelFile, read only the header row with nrows=0 or openpyxl read-only mode, detect hidden sheets and chartsheets, get each sheet's used range and build a catalogue of a folder of workbooks.","list-sheet-names-and-column-headers-without-loading-data","getting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Flist-sheet-names-and-column-headers-without-loading-data\u002Findex",[1998,1999],"reading-excel","large-files","how-to","Tolpc46H7vQkjpBv-dfVNP-yjTjPlW9ewcvNImYeWQQ",[2003,2007],{"title":2004,"path":2005,"stem":2006,"children":-1},"Keep Leading Zeros When Reading Excel with pandas","\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fkeep-leading-zeros-when-reading-excel-with-pandas","getting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fkeep-leading-zeros-when-reading-excel-with-pandas\u002Findex",{"title":2008,"path":2009,"stem":2010,"children":-1},"Read a Cell Range Like B3:F20 into a pandas DataFrame","\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-cell-range-into-a-pandas-dataframe","getting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-cell-range-into-a-pandas-dataframe\u002Findex",[2012,2014],{"path":2013,"title":1987},"\u002Fgetting-started-with-python-excel-automation",{"path":2015,"title":1990},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas",[],[2018,2021,2024,2027,2030,2033],{"path":2019,"title":2020,"kind":2000},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fread-an-excel-file-from-a-url-or-bytes-in-python","Read an Excel File from a URL or Bytes in Python",{"path":2022,"title":2023,"kind":2000},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Ffind-the-last-row-with-data-in-openpyxl","Find the Last Row with Data in openpyxl",{"path":2025,"title":2026,"kind":2000},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fiterate-over-rows-and-columns-with-openpyxl","Iterate over Rows and Columns with openpyxl",{"path":2028,"title":2029,"kind":2000},"\u002Fgetting-started-with-python-excel-automation\u002Fusing-openpyxl-for-excel-file-manipulation\u002Fread-cell-value-from-excel-with-openpyxl","Read a Cell Value From Excel With openpyxl",{"path":2031,"title":2032,"kind":2000},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fstandardise-excel-column-names-with-pandas","Standardise Excel Column Names with pandas",{"path":2034,"title":2035,"kind":2036},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets","Extracting Data from Messy Excel Sheets","guide",1790972065070]