[{"data":1,"prerenderedAt":2267},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-cell-range-into-a-pandas-dataframe":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-cell-range-into-a-pandas-dataframe":2232,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-cell-range-into-a-pandas-dataframe":2241,"children:\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-cell-range-into-a-pandas-dataframe":2246,"related:\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-cell-range-into-a-pandas-dataframe":2247},{"id":4,"title":5,"body":6,"dateModified":2198,"datePublished":2198,"description":2199,"extension":2200,"faq":2201,"keyword":2210,"kind":2211,"meta":2212,"navigation":446,"path":2221,"seo":2222,"slug":2225,"stem":2226,"topics":2227,"type":2230,"__hash__":2231},"docs\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-cell-range-into-a-pandas-dataframe\u002Findex.md","Read a Cell Range Like B3:F20 into a pandas DataFrame",{"type":7,"value":8,"toc":2183},"minimark",[9,24,374,379,407,414,418,469,472,476,494,595,606,627,646,780,784,791,932,938,1024,1043,1047,1054,1300,1311,1315,1326,1577,1585,1750,1754,1757,1990,1993,1997,2009,2013,2065,2069,2086,2090,2111,2115,2121,2127,2133,2139,2143,2179],[10,11,12,13,17,18,23],"p",{},"Real report sheets rarely start at A1. There is a title in the first row, a notes box off to the right, a total row under the data, maybe an appendix further down — and the table you want is the block from B3 to F7. ",[14,15,16],"code",{},"pd.read_excel"," reads the whole used area of the sheet by default, so all of that comes along with it. 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 two precise ways to read exactly one rectangular range, how to translate an A1 address into pandas arguments without off-by-one errors, and a helper that makes it a one-liner.",[25,26,34,35,34,39,34,43,34,51,34,58,34,67,34,71,34,77,34,81,34,85,34,89,34,93,34,97,34,101,34,105,34,109,34,112,34,116,34,120,34,125,34,129,34,134,34,137,34,141,34,143,34,145,34,147,34,149,34,151,34,153,34,156,34,160,34,162,34,166,34,170,34,172,34,175,34,177,34,180,34,182,34,185,34,187,34,190,34,193,34,197,34,199,34,201,34,205,34,207,34,210,34,212,34,215,34,217,34,220,34,222,34,225,34,228,34,232,34,234,34,236,34,239,34,241,34,244,34,246,34,249,34,251,34,254,34,256,34,259,34,262,34,266,34,268,34,270,34,273,34,275,34,278,34,280,34,283,34,285,34,288,34,290,34,293,34,296,34,300,34,302,34,304,34,307,34,309,34,312,34,314,34,317,34,319,34,322,34,324,34,327,34,330,34,334,34,336,34,338,34,340,34,342,34,344,34,346,34,349,34,353,34,355,34,359,34,363,34,365,34,367,34,370,34,372],"svg",{"viewBox":27,"role":28,"ariaLabelledBy":29,"xmlns":32,"style":33},"162 0 436 340","img",[30,31],"rcr-target-t","rcr-target-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:436px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[36,37,38],"title",{"id":30},"A table in the middle of a report sheet",[40,41,42],"desc",{"id":31},"A worksheet whose table occupies B3 to F7: a header row with Region, Manager, Q1, Q2 and Q3 and four data rows. Around it are a title in A1, a notes cell in H3, a total row in row 9 and an appendix starting at row 12, none of which should be read.",[44,45],"rect",{"x":46,"y":47,"width":48,"height":49,"fill":50},"162","0","436","340","#ffffff",[52,53,57],"text",{"x":54,"y":55,"style":56},"380.0","31.0","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","sales_report.xlsx — the block we want is B3:F7",[44,59],{"x":60,"y":61,"width":62,"height":63,"rx":47,"fill":64,"stroke":65,"style":66},"178.3","48.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[44,68],{"x":69,"y":61,"width":70,"height":63,"rx":47,"fill":64,"stroke":65,"style":66},"210.3","44.0",[52,72,76],{"x":73,"y":74,"style":75},"232.3","65.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[44,78],{"x":79,"y":61,"width":80,"height":63,"rx":47,"fill":64,"stroke":65,"style":66},"254.3","66.7",[52,82,84],{"x":83,"y":74,"style":75},"287.7","B",[44,86],{"x":87,"y":61,"width":88,"height":63,"rx":47,"fill":64,"stroke":65,"style":66},"321.1","78.8",[52,90,92],{"x":91,"y":74,"style":75},"360.5","C",[44,94],{"x":95,"y":61,"width":96,"height":63,"rx":47,"fill":64,"stroke":65,"style":66},"399.9","83.9",[52,98,100],{"x":99,"y":74,"style":75},"441.9","D",[44,102],{"x":103,"y":61,"width":104,"height":63,"rx":47,"fill":64,"stroke":65,"style":66},"483.8","48.9",[52,106,108],{"x":107,"y":74,"style":75},"508.3","E",[44,110],{"x":111,"y":61,"width":104,"height":63,"rx":47,"fill":64,"stroke":65,"style":66},"532.7",[52,113,115],{"x":114,"y":74,"style":75},"557.2","F",[44,117],{"x":60,"y":118,"width":62,"height":119,"rx":47,"fill":64,"stroke":65,"style":66},"72.0","28.0",[52,121,124],{"x":122,"y":123,"style":75},"194.3","91.0","1",[44,126],{"x":69,"y":118,"width":127,"height":119,"rx":47,"fill":64,"stroke":65,"style":128},"371.3","stroke-width:1.5px",[52,130,133],{"x":131,"y":123,"style":132},"396.0","font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Regional sales — prepared by Finance",[44,135],{"x":60,"y":136,"width":62,"height":119,"rx":47,"fill":64,"stroke":65,"style":66},"100.0",[52,138,140],{"x":122,"y":139,"style":75},"119.0","2",[44,142],{"x":69,"y":136,"width":70,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,144],{"x":79,"y":136,"width":80,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,146],{"x":87,"y":136,"width":88,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,148],{"x":95,"y":136,"width":96,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,150],{"x":103,"y":136,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,152],{"x":111,"y":136,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,154],{"x":60,"y":155,"width":62,"height":119,"rx":47,"fill":64,"stroke":65,"style":66},"128.0",[52,157,159],{"x":122,"y":158,"style":75},"147.0","3",[44,161],{"x":69,"y":155,"width":70,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,163],{"x":79,"y":155,"width":80,"height":119,"rx":47,"fill":164,"stroke":165,"style":128},"#d9f4f1","var(--teal,#0f9488)",[52,167,169],{"x":83,"y":158,"style":168},"font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","Region",[44,171],{"x":87,"y":155,"width":88,"height":119,"rx":47,"fill":164,"stroke":165,"style":128},[52,173,174],{"x":91,"y":158,"style":168},"Manager",[44,176],{"x":95,"y":155,"width":96,"height":119,"rx":47,"fill":164,"stroke":165,"style":128},[52,178,179],{"x":99,"y":158,"style":168},"Q1",[44,181],{"x":103,"y":155,"width":104,"height":119,"rx":47,"fill":164,"stroke":165,"style":128},[52,183,184],{"x":107,"y":158,"style":168},"Q2",[44,186],{"x":111,"y":155,"width":104,"height":119,"rx":47,"fill":164,"stroke":165,"style":128},[52,188,189],{"x":114,"y":158,"style":168},"Q3",[44,191],{"x":60,"y":192,"width":62,"height":119,"rx":47,"fill":64,"stroke":65,"style":66},"156.0",[52,194,196],{"x":122,"y":195,"style":75},"175.0","4",[44,198],{"x":69,"y":192,"width":70,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,200],{"x":79,"y":192,"width":80,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,202,204],{"x":83,"y":195,"style":203},"font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","North",[44,206],{"x":87,"y":192,"width":88,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,208,209],{"x":91,"y":195,"style":203},"Ada",[44,211],{"x":95,"y":192,"width":96,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,213,214],{"x":99,"y":195,"style":203},"410",[44,216],{"x":103,"y":192,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,218,219],{"x":107,"y":195,"style":203},"380",[44,221],{"x":111,"y":192,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,223,224],{"x":114,"y":195,"style":203},"402",[44,226],{"x":60,"y":227,"width":62,"height":119,"rx":47,"fill":64,"stroke":65,"style":66},"184.0",[52,229,231],{"x":122,"y":230,"style":75},"203.0","5",[44,233],{"x":69,"y":227,"width":70,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,235],{"x":79,"y":227,"width":80,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,237,238],{"x":83,"y":230,"style":203},"South",[44,240],{"x":87,"y":227,"width":88,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,242,243],{"x":91,"y":230,"style":203},"Ben",[44,245],{"x":95,"y":227,"width":96,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,247,248],{"x":99,"y":230,"style":203},"388",[44,250],{"x":103,"y":227,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,252,253],{"x":107,"y":230,"style":203},"395",[44,255],{"x":111,"y":227,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,257,258],{"x":114,"y":230,"style":203},"377",[44,260],{"x":60,"y":261,"width":62,"height":119,"rx":47,"fill":64,"stroke":65,"style":66},"212.0",[52,263,265],{"x":122,"y":264,"style":75},"231.0","6",[44,267],{"x":69,"y":261,"width":70,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,269],{"x":79,"y":261,"width":80,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,271,272],{"x":83,"y":264,"style":203},"East",[44,274],{"x":87,"y":261,"width":88,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,276,277],{"x":91,"y":264,"style":203},"Cleo",[44,279],{"x":95,"y":261,"width":96,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,281,282],{"x":99,"y":264,"style":203},"290",[44,284],{"x":103,"y":261,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,286,287],{"x":107,"y":264,"style":203},"301",[44,289],{"x":111,"y":261,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,291,292],{"x":114,"y":264,"style":203},"315",[44,294],{"x":60,"y":295,"width":62,"height":119,"rx":47,"fill":64,"stroke":65,"style":66},"240.0",[52,297,299],{"x":122,"y":298,"style":75},"259.0","7",[44,301],{"x":69,"y":295,"width":70,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,303],{"x":79,"y":295,"width":80,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,305,306],{"x":83,"y":298,"style":203},"West",[44,308],{"x":87,"y":295,"width":88,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,310,311],{"x":91,"y":298,"style":203},"Dev",[44,313],{"x":95,"y":295,"width":96,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,315,316],{"x":99,"y":298,"style":203},"505",[44,318],{"x":103,"y":295,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,320,321],{"x":107,"y":298,"style":203},"488",[44,323],{"x":111,"y":295,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[52,325,326],{"x":114,"y":298,"style":203},"530",[44,328],{"x":60,"y":329,"width":62,"height":119,"rx":47,"fill":64,"stroke":65,"style":66},"268.0",[52,331,333],{"x":122,"y":332,"style":75},"287.0","8",[44,335],{"x":69,"y":329,"width":70,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,337],{"x":79,"y":329,"width":80,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,339],{"x":87,"y":329,"width":88,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,341],{"x":95,"y":329,"width":96,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,343],{"x":103,"y":329,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,345],{"x":111,"y":329,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,347],{"x":60,"y":348,"width":62,"height":119,"rx":47,"fill":64,"stroke":65,"style":66},"296.0",[52,350,352],{"x":122,"y":351,"style":75},"315.0","9",[44,354],{"x":69,"y":348,"width":70,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,356],{"x":79,"y":348,"width":80,"height":119,"rx":47,"fill":357,"stroke":358,"style":128},"#fdefd8","var(--gold,#b4740a)",[52,360,362],{"x":83,"y":351,"style":361},"font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","Total",[44,364],{"x":87,"y":348,"width":88,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,366],{"x":95,"y":348,"width":96,"height":119,"rx":47,"fill":357,"stroke":358,"style":128},[52,368,369],{"x":99,"y":351,"style":361},"=SUM(…)",[44,371],{"x":103,"y":348,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[44,373],{"x":111,"y":348,"width":104,"height":119,"rx":47,"fill":50,"stroke":65,"style":66},[375,376,378],"h2",{"id":377},"prerequisites","Prerequisites",[380,381,386],"pre",{"className":382,"code":383,"language":384,"meta":385,"style":385},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[14,387,388],{"__ignoreMap":385},[389,390,393,397,401,404],"span",{"class":391,"line":392},"line",1,[389,394,396],{"class":395},"sMTad","pip",[389,398,400],{"class":399},"srMev"," install",[389,402,403],{"class":399}," pandas",[389,405,406],{"class":399}," openpyxl\n",[10,408,409,410,413],{},"The examples read ",[14,411,412],{},"sales_report.xlsx",", laid out as in the diagram: a title in A1, a table from B3 to F7, a total row at row 9, an appendix from row 12, and a note in H3.",[375,415,417],{"id":416},"step-1-see-the-problem-with-a-plain-read","Step 1 — See the problem with a plain read",[380,419,423],{"className":420,"code":421,"language":422,"meta":385,"style":385},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\n\nprint(pd.read_excel(\"sales_report.xlsx\").head(3))\n","python",[14,424,425,441,448],{"__ignoreMap":385},[389,426,427,431,435,438],{"class":391,"line":392},[389,428,430],{"class":429},"s-kum","import",[389,432,434],{"class":433},"skGVy"," pandas ",[389,436,437],{"class":429},"as",[389,439,440],{"class":433}," pd\n",[389,442,444],{"class":391,"line":443},2,[389,445,447],{"emptyLinePlaceholder":446},true,"\n",[389,449,451,455,458,461,464,466],{"class":391,"line":450},3,[389,452,454],{"class":453},"sP0c6","print",[389,456,457],{"class":433},"(pd.read_excel(",[389,459,460],{"class":399},"\"sales_report.xlsx\"",[389,462,463],{"class":433},").head(",[389,465,159],{"class":453},[389,467,468],{"class":433},"))\n",[10,470,471],{},"The title becomes the column header, the notes cell adds a column, and the total and appendix rows come along at the bottom. Cleaning that up afterwards is possible but fragile; reading only the block you want is cleaner.",[375,473,475],{"id":474},"step-2-translate-the-address-into-read_excel-arguments","Step 2 — Translate the address into read_excel arguments",[10,477,478,481,482,485,486,489,490,493],{},[14,479,480],{},"read_excel"," has three arguments that together select a rectangle: ",[14,483,484],{},"usecols"," picks columns, ",[14,487,488],{},"skiprows"," skips rows above the header, and ",[14,491,492],{},"nrows"," limits how many data rows are read after it. For a block whose first row is a header:",[380,495,497],{"className":420,"code":496,"language":422,"meta":385,"style":385},"table = pd.read_excel(\n    \"sales_report.xlsx\",\n    sheet_name=\"Report\",\n    usecols=\"B:F\",     # columns B to F\n    skiprows=2,        # skip rows 1-2, so row 3 is the header\n    nrows=4,           # data rows 4-7\n)\nprint(table)\n",[14,498,499,510,518,531,549,565,581,587],{"__ignoreMap":385},[389,500,501,504,507],{"class":391,"line":392},[389,502,503],{"class":433},"table ",[389,505,506],{"class":429},"=",[389,508,509],{"class":433}," pd.read_excel(\n",[389,511,512,515],{"class":391,"line":443},[389,513,514],{"class":399},"    \"sales_report.xlsx\"",[389,516,517],{"class":433},",\n",[389,519,520,524,526,529],{"class":391,"line":450},[389,521,523],{"class":522},"sa561","    sheet_name",[389,525,506],{"class":429},[389,527,528],{"class":399},"\"Report\"",[389,530,517],{"class":433},[389,532,534,537,539,542,545],{"class":391,"line":533},4,[389,535,536],{"class":522},"    usecols",[389,538,506],{"class":429},[389,540,541],{"class":399},"\"B:F\"",[389,543,544],{"class":433},",     ",[389,546,548],{"class":547},"s-wDw","# columns B to F\n",[389,550,552,555,557,559,562],{"class":391,"line":551},5,[389,553,554],{"class":522},"    skiprows",[389,556,506],{"class":429},[389,558,140],{"class":453},[389,560,561],{"class":433},",        ",[389,563,564],{"class":547},"# skip rows 1-2, so row 3 is the header\n",[389,566,568,571,573,575,578],{"class":391,"line":567},6,[389,569,570],{"class":522},"    nrows",[389,572,506],{"class":429},[389,574,196],{"class":453},[389,576,577],{"class":433},",           ",[389,579,580],{"class":547},"# data rows 4-7\n",[389,582,584],{"class":391,"line":583},7,[389,585,586],{"class":433},")\n",[389,588,590,592],{"class":391,"line":589},8,[389,591,454],{"class":453},[389,593,594],{"class":433},"(table)\n",[10,596,597,598,601,602,605],{},"The arithmetic is where mistakes happen, so make it explicit. For a range whose top-left cell is on row ",[14,599,600],{},"top"," and bottom row is ",[14,603,604],{},"bottom",", with the header on the first row:",[607,608,609,621],"ul",{},[610,611,612,615,616,620],"li",{},[14,613,614],{},"skiprows = top - 1"," — the number of rows ",[617,618,619],"em",{},"above"," the header;",[610,622,623,626],{},[14,624,625],{},"nrows = bottom - top"," — data rows only, because the header row is not counted.",[10,628,629,630,633,634,637,638,641,642,645],{},"For ",[14,631,632],{},"B3:F7"," that gives ",[14,635,636],{},"skiprows=2"," and ",[14,639,640],{},"nrows=4",". A common slip is ",[14,643,644],{},"nrows=5",", which quietly pulls in row 8 — blank here, but in many sheets the first row of a total or of the next table.",[25,647,34,653,34,656,34,659,34,663,34,671,34,682,34,688,34,693,34,697,34,703,34,708,34,712,34,719,34,725,34,729,34,733,34,736,34,739,34,746,34,750,34,753,34,756,34,760,34,763,34,766,34,773,34,777],{"viewBox":648,"role":28,"ariaLabelledBy":649,"xmlns":32,"style":652},"4 0 752 142",[650,651],"rcr-args-t","rcr-args-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[36,654,655],{"id":650},"From \"B3:F7\" to read_excel arguments",[40,657,658],{"id":651},"The address B3:F7 splits into columns B to F and rows 3 to 7. Columns become usecols=\"B:F\". The top row 3 becomes skiprows=2, the number of rows above it. The rows after the header, 4 to 7, become nrows=4.",[44,660],{"x":196,"y":47,"width":661,"height":662,"fill":50},"752","142",[44,664],{"x":665,"y":666,"width":667,"height":668,"rx":669,"fill":64,"stroke":65,"style":670},"20.0","16.0","153.0","110.5","12","stroke-width:2px",[672,673,675],"g",{"transform":674},"translate(84.5,29.0) scale(1.000)",[676,677],"path",{"d":678,"fill":679,"stroke":680,"style":681},"M4 4h16v16H4z M4 9h16 M4 14h16 M10 4v16","none","var(--text,#172033)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[52,683,687],{"x":684,"y":685,"style":686},"96.5","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Address B3:F7",[52,689,692],{"x":684,"y":690,"style":691},"95.0","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","columns B–F, rows",[52,694,696],{"x":684,"y":695,"style":691},"112.5","3–7",[391,698],{"x1":699,"y1":700,"x2":701,"y2":700,"stroke":702,"style":670},"178.0","71.2","200.0","var(--brand,#5b5cf0)",[704,705],"polygon",{"points":706,"fill":707},"204.0,71.2 195.0,76.2 195.0,66.2","#5b5cf0",[44,709],{"x":710,"y":666,"width":667,"height":668,"rx":669,"fill":711,"stroke":702,"style":670},"209.0","#f0f4ff",[672,713,715],{"transform":714},"translate(273.5,37.8) scale(1.000)",[676,716],{"d":717,"fill":679,"stroke":718,"style":681},"M3 5h18v14H3z M3 10h18 M3 15h18 M9 5v14","var(--brand-strong,#4338ca)",[52,720,724],{"x":721,"y":722,"style":723},"285.5","84.2","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","usecols=\"B:F\"",[52,726,728],{"x":721,"y":727,"style":691},"103.8","columns B to F",[391,730],{"x1":731,"y1":700,"x2":732,"y2":700,"stroke":702,"style":670},"367.0","389.0",[704,734],{"points":735,"fill":707},"393.0,71.2 384.0,76.2 384.0,66.2",[44,737],{"x":738,"y":666,"width":667,"height":668,"rx":669,"fill":164,"stroke":165,"style":670},"398.0",[672,740,742],{"transform":741},"translate(462.5,29.0) scale(1.000)",[676,743],{"d":744,"fill":679,"stroke":745,"style":681},"M3 5h18l-7 8v6l-4 2v-8z","var(--teal-ink,#0b6157)",[52,747,636],{"x":748,"y":685,"style":749},"474.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle",[52,751,752],{"x":748,"y":690,"style":691},"rows above the",[52,754,755],{"x":748,"y":695,"style":691},"header: 3 − 1",[391,757],{"x1":758,"y1":700,"x2":759,"y2":700,"stroke":702,"style":670},"556.0","578.0",[704,761],{"points":762,"fill":707},"582.0,71.2 573.0,76.2 573.0,66.2",[44,764],{"x":765,"y":666,"width":667,"height":668,"rx":669,"fill":357,"stroke":358,"style":670},"587.0",[672,767,769],{"transform":768},"translate(651.5,37.8) scale(1.000)",[676,770],{"d":771,"fill":679,"stroke":772,"style":681},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","var(--gold-ink,#7a4e06)",[52,774,640],{"x":775,"y":722,"style":776},"663.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle",[52,778,779],{"x":775,"y":727,"style":691},"data rows: 7 − 3",[375,781,783],{"id":782},"step-3-or-read-the-range-with-openpyxl","Step 3 — Or read the range with openpyxl",[10,785,786,787,790],{},"When you have the address as a string, openpyxl can take it directly. Indexing a worksheet with ",[14,788,789],{},"\"B3:F7\""," returns a tuple of rows, each a tuple of cells; turn the first row into the header and the rest into data:",[380,792,794],{"className":420,"code":793,"language":422,"meta":385,"style":385},"from openpyxl import load_workbook\n\nwb = load_workbook(\"sales_report.xlsx\", data_only=True)\nws = wb[\"Report\"]\ncells = ws[\"B3:F7\"]\nvalues = [[c.value for c in row] for row in cells]\ntable = pd.DataFrame(values[1:], columns=values[0])\nprint(table)\n",[14,795,796,809,813,838,853,867,899,926],{"__ignoreMap":385},[389,797,798,801,804,806],{"class":391,"line":392},[389,799,800],{"class":429},"from",[389,802,803],{"class":433}," openpyxl ",[389,805,430],{"class":429},[389,807,808],{"class":433}," load_workbook\n",[389,810,811],{"class":391,"line":443},[389,812,447],{"emptyLinePlaceholder":446},[389,814,815,818,820,823,825,828,831,833,836],{"class":391,"line":450},[389,816,817],{"class":433},"wb ",[389,819,506],{"class":429},[389,821,822],{"class":433}," load_workbook(",[389,824,460],{"class":399},[389,826,827],{"class":433},", ",[389,829,830],{"class":522},"data_only",[389,832,506],{"class":429},[389,834,835],{"class":453},"True",[389,837,586],{"class":433},[389,839,840,843,845,848,850],{"class":391,"line":533},[389,841,842],{"class":433},"ws ",[389,844,506],{"class":429},[389,846,847],{"class":433}," wb[",[389,849,528],{"class":399},[389,851,852],{"class":433},"]\n",[389,854,855,858,860,863,865],{"class":391,"line":551},[389,856,857],{"class":433},"cells ",[389,859,506],{"class":429},[389,861,862],{"class":433}," ws[",[389,864,789],{"class":399},[389,866,852],{"class":433},[389,868,869,872,874,877,880,883,886,889,891,894,896],{"class":391,"line":567},[389,870,871],{"class":433},"values ",[389,873,506],{"class":429},[389,875,876],{"class":433}," [[c.value ",[389,878,879],{"class":429},"for",[389,881,882],{"class":433}," c ",[389,884,885],{"class":429},"in",[389,887,888],{"class":433}," row] ",[389,890,879],{"class":429},[389,892,893],{"class":433}," row ",[389,895,885],{"class":429},[389,897,898],{"class":433}," cells]\n",[389,900,901,903,905,908,910,913,916,918,921,923],{"class":391,"line":583},[389,902,503],{"class":433},[389,904,506],{"class":429},[389,906,907],{"class":433}," pd.DataFrame(values[",[389,909,124],{"class":453},[389,911,912],{"class":433},":], ",[389,914,915],{"class":522},"columns",[389,917,506],{"class":429},[389,919,920],{"class":433},"values[",[389,922,47],{"class":453},[389,924,925],{"class":433},"])\n",[389,927,928,930],{"class":391,"line":589},[389,929,454],{"class":453},[389,931,594],{"class":433},[10,933,934,937],{},[14,935,936],{},"iter_rows"," does the same with numbers instead of letters and can return values directly, which avoids building cell objects you do not need:",[380,939,941],{"className":420,"code":940,"language":422,"meta":385,"style":385},"rows = list(ws.iter_rows(min_row=3, max_row=7, min_col=2, max_col=6, values_only=True))\nprint(pd.DataFrame(rows[1:], columns=rows[0]).equals(table))\n",[14,942,943,1001],{"__ignoreMap":385},[389,944,945,948,950,953,956,959,961,963,965,968,970,972,974,977,979,981,983,986,988,990,992,995,997,999],{"class":391,"line":392},[389,946,947],{"class":433},"rows ",[389,949,506],{"class":429},[389,951,952],{"class":453}," list",[389,954,955],{"class":433},"(ws.iter_rows(",[389,957,958],{"class":522},"min_row",[389,960,506],{"class":429},[389,962,159],{"class":453},[389,964,827],{"class":433},[389,966,967],{"class":522},"max_row",[389,969,506],{"class":429},[389,971,299],{"class":453},[389,973,827],{"class":433},[389,975,976],{"class":522},"min_col",[389,978,506],{"class":429},[389,980,140],{"class":453},[389,982,827],{"class":433},[389,984,985],{"class":522},"max_col",[389,987,506],{"class":429},[389,989,265],{"class":453},[389,991,827],{"class":433},[389,993,994],{"class":522},"values_only",[389,996,506],{"class":429},[389,998,835],{"class":453},[389,1000,468],{"class":433},[389,1002,1003,1005,1008,1010,1012,1014,1016,1019,1021],{"class":391,"line":443},[389,1004,454],{"class":453},[389,1006,1007],{"class":433},"(pd.DataFrame(rows[",[389,1009,124],{"class":453},[389,1011,912],{"class":433},[389,1013,915],{"class":522},[389,1015,506],{"class":429},[389,1017,1018],{"class":433},"rows[",[389,1020,47],{"class":453},[389,1022,1023],{"class":433},"]).equals(table))\n",[10,1025,1026,1029,1030,1033,1034,1037,1038,1042],{},[14,1027,1028],{},"data_only=True"," matters for any range containing formulas. Without it, openpyxl returns the formula text — ",[14,1031,1032],{},"'=SUM(D4:D7)'"," — rather than the number. With it, you get the value that was cached when a spreadsheet application last saved the file. A workbook written by openpyxl itself has no cached values, so its formula cells read as ",[14,1035,1036],{},"None","; ",[19,1039,1041],{"href":1040},"\u002Fgetting-started-with-python-excel-automation\u002Fworking-with-excel-formulas-in-python\u002Fread-formula-results-with-openpyxl-data-only\u002F","Read Formula Results with openpyxl data_only"," explains when to recalculate first.",[375,1044,1046],{"id":1045},"step-4-wrap-it-in-a-read_range-helper","Step 4 — Wrap it in a read_range helper",[10,1048,1049,1050,1053],{},"Most scripts that need a range get the address from configuration or from a colleague: \"the numbers are in B3:F7 on the Report tab\". A helper that accepts exactly that is worth having. openpyxl's ",[14,1051,1052],{},"range_boundaries"," does the parsing, and the function supports ranges with or without a header row:",[380,1055,1057],{"className":420,"code":1056,"language":422,"meta":385,"style":385},"from openpyxl.utils.cell import range_boundaries\n\ndef read_range(path, sheet, address, header=True):\n    min_col, min_row, max_col, max_row = range_boundaries(address)\n    wb = load_workbook(path, read_only=True, data_only=True)\n    try:\n        rows = list(wb[sheet].iter_rows(min_row=min_row, max_row=max_row,\n                                        min_col=min_col, max_col=max_col, values_only=True))\n    finally:\n        wb.close()\n    if header:\n        return pd.DataFrame(rows[1:], columns=rows[0])\n    return pd.DataFrame(rows)\n\nprint(read_range(\"sales_report.xlsx\", \"Report\", \"B3:F7\"))\nprint(read_range(\"sales_report.xlsx\", \"Report\", \"B13:C13\", header=False))\n",[14,1058,1059,1071,1075,1094,1104,1131,1139,1165,1190,1198,1204,1213,1236,1245,1250,1270],{"__ignoreMap":385},[389,1060,1061,1063,1066,1068],{"class":391,"line":392},[389,1062,800],{"class":429},[389,1064,1065],{"class":433}," openpyxl.utils.cell ",[389,1067,430],{"class":429},[389,1069,1070],{"class":433}," range_boundaries\n",[389,1072,1073],{"class":391,"line":443},[389,1074,447],{"emptyLinePlaceholder":446},[389,1076,1077,1080,1084,1087,1089,1091],{"class":391,"line":450},[389,1078,1079],{"class":429},"def",[389,1081,1083],{"class":1082},"s_Opv"," read_range",[389,1085,1086],{"class":433},"(path, sheet, address, header",[389,1088,506],{"class":429},[389,1090,835],{"class":453},[389,1092,1093],{"class":433},"):\n",[389,1095,1096,1099,1101],{"class":391,"line":533},[389,1097,1098],{"class":433},"    min_col, min_row, max_col, max_row ",[389,1100,506],{"class":429},[389,1102,1103],{"class":433}," range_boundaries(address)\n",[389,1105,1106,1109,1111,1114,1117,1119,1121,1123,1125,1127,1129],{"class":391,"line":551},[389,1107,1108],{"class":433},"    wb ",[389,1110,506],{"class":429},[389,1112,1113],{"class":433}," load_workbook(path, ",[389,1115,1116],{"class":522},"read_only",[389,1118,506],{"class":429},[389,1120,835],{"class":453},[389,1122,827],{"class":433},[389,1124,830],{"class":522},[389,1126,506],{"class":429},[389,1128,835],{"class":453},[389,1130,586],{"class":433},[389,1132,1133,1136],{"class":391,"line":567},[389,1134,1135],{"class":429},"    try",[389,1137,1138],{"class":433},":\n",[389,1140,1141,1144,1146,1148,1151,1153,1155,1158,1160,1162],{"class":391,"line":583},[389,1142,1143],{"class":433},"        rows ",[389,1145,506],{"class":429},[389,1147,952],{"class":453},[389,1149,1150],{"class":433},"(wb[sheet].iter_rows(",[389,1152,958],{"class":522},[389,1154,506],{"class":429},[389,1156,1157],{"class":433},"min_row, ",[389,1159,967],{"class":522},[389,1161,506],{"class":429},[389,1163,1164],{"class":433},"max_row,\n",[389,1166,1167,1170,1172,1175,1177,1179,1182,1184,1186,1188],{"class":391,"line":589},[389,1168,1169],{"class":522},"                                        min_col",[389,1171,506],{"class":429},[389,1173,1174],{"class":433},"min_col, ",[389,1176,985],{"class":522},[389,1178,506],{"class":429},[389,1180,1181],{"class":433},"max_col, ",[389,1183,994],{"class":522},[389,1185,506],{"class":429},[389,1187,835],{"class":453},[389,1189,468],{"class":433},[389,1191,1193,1196],{"class":391,"line":1192},9,[389,1194,1195],{"class":429},"    finally",[389,1197,1138],{"class":433},[389,1199,1201],{"class":391,"line":1200},10,[389,1202,1203],{"class":433},"        wb.close()\n",[389,1205,1207,1210],{"class":391,"line":1206},11,[389,1208,1209],{"class":429},"    if",[389,1211,1212],{"class":433}," header:\n",[389,1214,1216,1219,1222,1224,1226,1228,1230,1232,1234],{"class":391,"line":1215},12,[389,1217,1218],{"class":429},"        return",[389,1220,1221],{"class":433}," pd.DataFrame(rows[",[389,1223,124],{"class":453},[389,1225,912],{"class":433},[389,1227,915],{"class":522},[389,1229,506],{"class":429},[389,1231,1018],{"class":433},[389,1233,47],{"class":453},[389,1235,925],{"class":433},[389,1237,1239,1242],{"class":391,"line":1238},13,[389,1240,1241],{"class":429},"    return",[389,1243,1244],{"class":433}," pd.DataFrame(rows)\n",[389,1246,1248],{"class":391,"line":1247},14,[389,1249,447],{"emptyLinePlaceholder":446},[389,1251,1253,1255,1258,1260,1262,1264,1266,1268],{"class":391,"line":1252},15,[389,1254,454],{"class":453},[389,1256,1257],{"class":433},"(read_range(",[389,1259,460],{"class":399},[389,1261,827],{"class":433},[389,1263,528],{"class":399},[389,1265,827],{"class":433},[389,1267,789],{"class":399},[389,1269,468],{"class":433},[389,1271,1273,1275,1277,1279,1281,1283,1285,1288,1290,1293,1295,1298],{"class":391,"line":1272},16,[389,1274,454],{"class":453},[389,1276,1257],{"class":433},[389,1278,460],{"class":399},[389,1280,827],{"class":433},[389,1282,528],{"class":399},[389,1284,827],{"class":433},[389,1286,1287],{"class":399},"\"B13:C13\"",[389,1289,827],{"class":433},[389,1291,1292],{"class":522},"header",[389,1294,506],{"class":429},[389,1296,1297],{"class":453},"False",[389,1299,468],{"class":433},[10,1301,1302,1303,1306,1307,1310],{},"Opening in read-only mode keeps memory flat even when the sheet is large, and the ",[14,1304,1305],{},"try","\u002F",[14,1308,1309],{},"finally"," closes the file handle, which read-only workbooks hold open until closed. The second call reads a headerless block — the appendix row — as positional columns 0 and 1.",[375,1312,1314],{"id":1313},"step-5-handle-a-range-whose-size-changes","Step 5 — Handle a range whose size changes",[10,1316,1317,1318,1321,1322,1325],{},"A fixed address is right when the layout is fixed. When the table grows each month, hard-coding ",[14,1319,1320],{},"F7"," either misses new rows or, if you pad it to ",[14,1323,1324],{},"F200",", reads the total row and the appendix. Read from the top-left corner to the first empty row instead:",[380,1327,1329],{"className":420,"code":1328,"language":422,"meta":385,"style":385},"def read_block(path, sheet, top_left, width):\n    min_col, min_row, _, _ = range_boundaries(f\"{top_left}:{top_left}\")\n    wb = load_workbook(path, read_only=True, data_only=True)\n    try:\n        rows = []\n        for row in wb[sheet].iter_rows(min_row=min_row, min_col=min_col,\n                                       max_col=min_col + width - 1, values_only=True):\n            if all(v is None for v in row):\n                break\n            rows.append(row)\n    finally:\n        wb.close()\n    return pd.DataFrame(rows[1:], columns=rows[0])\n\nprint(read_block(\"sales_report.xlsx\", \"Report\", \"B3\", width=5))\n",[14,1330,1331,1341,1380,1404,1410,1419,1444,1476,1504,1509,1514,1520,1524,1544,1548],{"__ignoreMap":385},[389,1332,1333,1335,1338],{"class":391,"line":392},[389,1334,1079],{"class":429},[389,1336,1337],{"class":1082}," read_block",[389,1339,1340],{"class":433},"(path, sheet, top_left, width):\n",[389,1342,1343,1346,1348,1351,1354,1357,1361,1364,1367,1370,1372,1374,1376,1378],{"class":391,"line":443},[389,1344,1345],{"class":433},"    min_col, min_row, _, _ ",[389,1347,506],{"class":429},[389,1349,1350],{"class":433}," range_boundaries(",[389,1352,1353],{"class":429},"f",[389,1355,1356],{"class":399},"\"",[389,1358,1360],{"class":1359},"sSjpA","{",[389,1362,1363],{"class":433},"top_left",[389,1365,1366],{"class":1359},"}",[389,1368,1369],{"class":399},":",[389,1371,1360],{"class":1359},[389,1373,1363],{"class":433},[389,1375,1366],{"class":1359},[389,1377,1356],{"class":399},[389,1379,586],{"class":433},[389,1381,1382,1384,1386,1388,1390,1392,1394,1396,1398,1400,1402],{"class":391,"line":450},[389,1383,1108],{"class":433},[389,1385,506],{"class":429},[389,1387,1113],{"class":433},[389,1389,1116],{"class":522},[389,1391,506],{"class":429},[389,1393,835],{"class":453},[389,1395,827],{"class":433},[389,1397,830],{"class":522},[389,1399,506],{"class":429},[389,1401,835],{"class":453},[389,1403,586],{"class":433},[389,1405,1406,1408],{"class":391,"line":533},[389,1407,1135],{"class":429},[389,1409,1138],{"class":433},[389,1411,1412,1414,1416],{"class":391,"line":551},[389,1413,1143],{"class":433},[389,1415,506],{"class":429},[389,1417,1418],{"class":433}," []\n",[389,1420,1421,1424,1426,1428,1431,1433,1435,1437,1439,1441],{"class":391,"line":567},[389,1422,1423],{"class":429},"        for",[389,1425,893],{"class":433},[389,1427,885],{"class":429},[389,1429,1430],{"class":433}," wb[sheet].iter_rows(",[389,1432,958],{"class":522},[389,1434,506],{"class":429},[389,1436,1157],{"class":433},[389,1438,976],{"class":522},[389,1440,506],{"class":429},[389,1442,1443],{"class":433},"min_col,\n",[389,1445,1446,1449,1451,1454,1457,1460,1463,1466,1468,1470,1472,1474],{"class":391,"line":583},[389,1447,1448],{"class":522},"                                       max_col",[389,1450,506],{"class":429},[389,1452,1453],{"class":433},"min_col ",[389,1455,1456],{"class":429},"+",[389,1458,1459],{"class":433}," width ",[389,1461,1462],{"class":429},"-",[389,1464,1465],{"class":453}," 1",[389,1467,827],{"class":433},[389,1469,994],{"class":522},[389,1471,506],{"class":429},[389,1473,835],{"class":453},[389,1475,1093],{"class":433},[389,1477,1478,1481,1484,1487,1490,1493,1496,1499,1501],{"class":391,"line":589},[389,1479,1480],{"class":429},"            if",[389,1482,1483],{"class":453}," all",[389,1485,1486],{"class":433},"(v ",[389,1488,1489],{"class":429},"is",[389,1491,1492],{"class":453}," None",[389,1494,1495],{"class":429}," for",[389,1497,1498],{"class":433}," v ",[389,1500,885],{"class":429},[389,1502,1503],{"class":433}," row):\n",[389,1505,1506],{"class":391,"line":1192},[389,1507,1508],{"class":429},"                break\n",[389,1510,1511],{"class":391,"line":1200},[389,1512,1513],{"class":433},"            rows.append(row)\n",[389,1515,1516,1518],{"class":391,"line":1206},[389,1517,1195],{"class":429},[389,1519,1138],{"class":433},[389,1521,1522],{"class":391,"line":1215},[389,1523,1203],{"class":433},[389,1525,1526,1528,1530,1532,1534,1536,1538,1540,1542],{"class":391,"line":1238},[389,1527,1241],{"class":429},[389,1529,1221],{"class":433},[389,1531,124],{"class":453},[389,1533,912],{"class":433},[389,1535,915],{"class":522},[389,1537,506],{"class":429},[389,1539,1018],{"class":433},[389,1541,47],{"class":453},[389,1543,925],{"class":433},[389,1545,1546],{"class":391,"line":1247},[389,1547,447],{"emptyLinePlaceholder":446},[389,1549,1550,1552,1555,1557,1559,1561,1563,1566,1568,1571,1573,1575],{"class":391,"line":1252},[389,1551,454],{"class":453},[389,1553,1554],{"class":433},"(read_block(",[389,1556,460],{"class":399},[389,1558,827],{"class":433},[389,1560,528],{"class":399},[389,1562,827],{"class":433},[389,1564,1565],{"class":399},"\"B3\"",[389,1567,827],{"class":433},[389,1569,1570],{"class":522},"width",[389,1572,506],{"class":429},[389,1574,231],{"class":453},[389,1576,468],{"class":433},[10,1578,1579,1580,1584],{},"Stopping at the first completely blank row works for the common layout of a table followed by a gap. If the first column can be blank inside the data, test a key column instead of the whole row. When even the header row moves, search for a known label first; ",[19,1581,1583],{"href":1582},"\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"," shows how.",[25,1586,34,1591,34,1594,34,1597,34,1599,34,1603,34,1609,34,1612,34,1616,34,1620,34,1623,34,1626,34,1634,34,1639,34,1643,34,1648,34,1651,34,1655,34,1659,34,1662,34,1665,34,1669,34,1672,34,1675,34,1681,34,1684,34,1688,34,1690,34,1693,34,1696,34,1700,34,1703,34,1706,34,1712,34,1715,34,1718,34,1721,34,1723,34,1726,34,1730,34,1733,34,1736,34,1742,34,1746],{"viewBox":1587,"role":28,"ariaLabelledBy":1588,"xmlns":32,"style":652},"4 0 752 290",[1589,1590],"rcr-which-t","rcr-which-d",[36,1592,1593],{"id":1589},"Which way to read a range",[40,1595,1596],{"id":1590},"A decision chart. If the address is fixed and the block starts with a header, use read_excel with usecols, skiprows and nrows. If the address arrives as an A1 string or there is no header, use openpyxl with a read_range helper. If the block grows over time, read from the top-left cell to the first blank row. If the block is an Excel table or named range, read it by name.",[44,1598],{"x":196,"y":47,"width":661,"height":282,"fill":50},[44,1600],{"x":1601,"y":666,"width":1602,"height":685,"rx":669,"fill":711,"stroke":702,"style":670},"226.6","306.9",[672,1604,1606],{"transform":1605},"translate(368.0,29.0) scale(1.000)",[676,1607],{"d":1608,"fill":679,"stroke":718,"style":681},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5",[52,1610,1611],{"x":54,"y":685,"style":723},"What do you know about the block?",[391,1613],{"x1":54,"y1":1614,"x2":54,"y2":1615,"stroke":702,"style":670},"91.5","111.5",[391,1617],{"x1":1618,"y1":1615,"x2":1619,"y2":1615,"stroke":702,"style":670},"104.0","656.0",[391,1621],{"x1":1618,"y1":1615,"x2":1618,"y2":1622,"stroke":702,"style":670},"157.5",[704,1624],{"points":1625,"fill":707},"104.0,161.5 99.0,152.5 109.0,152.5",[44,1627],{"x":1628,"y":1629,"width":1630,"height":1631,"rx":1632,"fill":50,"stroke":65,"style":1633},"28.4","121.5","151.2","21.0","10","stroke-width:1.2px",[52,1635,1638],{"x":1618,"y":1636,"style":1637},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","fixed and has a header",[44,1640],{"x":665,"y":1641,"width":1642,"height":668,"rx":669,"fill":711,"stroke":702,"style":670},"163.5","168.0",[672,1644,1646],{"transform":1645},"translate(92.0,176.5) scale(1.000)",[676,1647],{"d":717,"fill":679,"stroke":718,"style":681},[52,1649,480],{"x":1618,"y":1650,"style":723},"223.0",[52,1652,1654],{"x":1618,"y":1653,"style":723},"240.5","arguments",[52,1656,1658],{"x":1618,"y":1657,"style":691},"260.0","usecols, skiprows, nrows",[391,1660],{"x1":1661,"y1":1615,"x2":1661,"y2":1622,"stroke":702,"style":670},"288.0",[704,1663],{"points":1664,"fill":707},"288.0,161.5 283.0,152.5 293.0,152.5",[44,1666],{"x":1667,"y":1629,"width":1668,"height":1631,"rx":1632,"fill":50,"stroke":65,"style":1633},"219.1","137.7",[52,1670,1671],{"x":1661,"y":1636,"style":1637},"an A1 address string",[44,1673],{"x":1674,"y":1641,"width":1642,"height":668,"rx":669,"fill":164,"stroke":165,"style":670},"204.0",[672,1676,1678],{"transform":1677},"translate(276.0,176.5) scale(1.000)",[676,1679],{"d":1680,"fill":679,"stroke":745,"style":681},"M9 8l-4 4 4 4 M15 8l4 4-4 4",[52,1682,1683],{"x":1661,"y":1650,"style":749},"read_range helper",[52,1685,1687],{"x":1661,"y":1686,"style":691},"242.5","openpyxl",[52,1689,1052],{"x":1661,"y":1657,"style":691},[391,1691],{"x1":1692,"y1":1615,"x2":1692,"y2":1622,"stroke":702,"style":670},"472.0",[704,1694],{"points":1695,"fill":707},"472.0,161.5 467.0,152.5 477.0,152.5",[44,1697],{"x":1698,"y":1629,"width":1699,"height":1631,"rx":1632,"fill":50,"stroke":65,"style":1633},"405.8","132.4",[52,1701,1702],{"x":1692,"y":1636,"style":1637},"grows every month",[44,1704],{"x":1705,"y":1641,"width":1642,"height":668,"rx":669,"fill":357,"stroke":358,"style":670},"388.0",[672,1707,1709],{"transform":1708},"translate(460.0,176.5) scale(1.000)",[676,1710],{"d":1711,"fill":679,"stroke":772,"style":681},"M20 11a8 8 0 1 0-2.3 5.7 M20 4v7h-7",[52,1713,1714],{"x":1692,"y":1650,"style":776},"Read to the first",[52,1716,1717],{"x":1692,"y":1653,"style":776},"blank row",[52,1719,1720],{"x":1692,"y":1657,"style":691},"read_block helper",[391,1722],{"x1":1619,"y1":1615,"x2":1619,"y2":1622,"stroke":702,"style":670},[704,1724],{"points":1725,"fill":707},"656.0,161.5 651.0,152.5 661.0,152.5",[44,1727],{"x":1728,"y":1629,"width":1729,"height":1631,"rx":1632,"fill":50,"stroke":65,"style":1633},"579.5","152.9",[52,1731,1732],{"x":1619,"y":1636,"style":1637},"a table or named range",[44,1734],{"x":1735,"y":1641,"width":1642,"height":668,"rx":669,"fill":64,"stroke":65,"style":670},"572.0",[672,1737,1739],{"transform":1738},"translate(644.0,185.2) scale(1.000)",[676,1740],{"d":1741,"fill":679,"stroke":680,"style":681},"M10 14a4 4 0 0 0 5.7 0l3-3a4 4 0 0 0-5.7-5.7l-1 1 M14 10a4 4 0 0 0-5.7 0l-3 3a4 4 0 0 0 5.7 5.7l1-1",[52,1743,1745],{"x":1619,"y":1744,"style":686},"231.8","Read it by name",[52,1747,1749],{"x":1619,"y":1748,"style":691},"251.2","survives layout changes",[375,1751,1753],{"id":1752},"read-several-ranges-in-one-pass","Read several ranges in one pass",[10,1755,1756],{},"Report sheets often hold more than one block you need — the main table plus a headcount appendix, say. Open the workbook once and read every range from it, rather than reopening the file for each:",[380,1758,1760],{"className":420,"code":1759,"language":422,"meta":385,"style":385},"RANGES = {\"sales\": (\"Report\", \"B3:F7\", True), \"headcount\": (\"Report\", \"B13:C13\", False)}\n\nwb = load_workbook(\"sales_report.xlsx\", read_only=True, data_only=True)\nframes = {}\ntry:\n    for key, (sheet, address, has_header) in RANGES.items():\n        min_col, min_row, max_col, max_row = range_boundaries(address)\n        rows = list(wb[sheet].iter_rows(min_row=min_row, max_row=max_row,\n                                        min_col=min_col, max_col=max_col, values_only=True))\n        frames[key] = pd.DataFrame(rows[1:], columns=rows[0]) if has_header else pd.DataFrame(rows)\nfinally:\n    wb.close()\nprint({k: v.shape for k, v in frames.items()})\n",[14,1761,1762,1810,1814,1842,1852,1858,1874,1883,1905,1927,1962,1968,1973],{"__ignoreMap":385},[389,1763,1764,1767,1770,1773,1776,1779,1781,1783,1785,1787,1789,1792,1795,1797,1799,1801,1803,1805,1807],{"class":391,"line":392},[389,1765,1766],{"class":453},"RANGES",[389,1768,1769],{"class":429}," =",[389,1771,1772],{"class":433}," {",[389,1774,1775],{"class":399},"\"sales\"",[389,1777,1778],{"class":433},": (",[389,1780,528],{"class":399},[389,1782,827],{"class":433},[389,1784,789],{"class":399},[389,1786,827],{"class":433},[389,1788,835],{"class":453},[389,1790,1791],{"class":433},"), ",[389,1793,1794],{"class":399},"\"headcount\"",[389,1796,1778],{"class":433},[389,1798,528],{"class":399},[389,1800,827],{"class":433},[389,1802,1287],{"class":399},[389,1804,827],{"class":433},[389,1806,1297],{"class":453},[389,1808,1809],{"class":433},")}\n",[389,1811,1812],{"class":391,"line":443},[389,1813,447],{"emptyLinePlaceholder":446},[389,1815,1816,1818,1820,1822,1824,1826,1828,1830,1832,1834,1836,1838,1840],{"class":391,"line":450},[389,1817,817],{"class":433},[389,1819,506],{"class":429},[389,1821,822],{"class":433},[389,1823,460],{"class":399},[389,1825,827],{"class":433},[389,1827,1116],{"class":522},[389,1829,506],{"class":429},[389,1831,835],{"class":453},[389,1833,827],{"class":433},[389,1835,830],{"class":522},[389,1837,506],{"class":429},[389,1839,835],{"class":453},[389,1841,586],{"class":433},[389,1843,1844,1847,1849],{"class":391,"line":533},[389,1845,1846],{"class":433},"frames ",[389,1848,506],{"class":429},[389,1850,1851],{"class":433}," {}\n",[389,1853,1854,1856],{"class":391,"line":551},[389,1855,1305],{"class":429},[389,1857,1138],{"class":433},[389,1859,1860,1863,1866,1868,1871],{"class":391,"line":567},[389,1861,1862],{"class":429},"    for",[389,1864,1865],{"class":433}," key, (sheet, address, has_header) ",[389,1867,885],{"class":429},[389,1869,1870],{"class":453}," RANGES",[389,1872,1873],{"class":433},".items():\n",[389,1875,1876,1879,1881],{"class":391,"line":583},[389,1877,1878],{"class":433},"        min_col, min_row, max_col, max_row ",[389,1880,506],{"class":429},[389,1882,1103],{"class":433},[389,1884,1885,1887,1889,1891,1893,1895,1897,1899,1901,1903],{"class":391,"line":589},[389,1886,1143],{"class":433},[389,1888,506],{"class":429},[389,1890,952],{"class":453},[389,1892,1150],{"class":433},[389,1894,958],{"class":522},[389,1896,506],{"class":429},[389,1898,1157],{"class":433},[389,1900,967],{"class":522},[389,1902,506],{"class":429},[389,1904,1164],{"class":433},[389,1906,1907,1909,1911,1913,1915,1917,1919,1921,1923,1925],{"class":391,"line":1192},[389,1908,1169],{"class":522},[389,1910,506],{"class":429},[389,1912,1174],{"class":433},[389,1914,985],{"class":522},[389,1916,506],{"class":429},[389,1918,1181],{"class":433},[389,1920,994],{"class":522},[389,1922,506],{"class":429},[389,1924,835],{"class":453},[389,1926,468],{"class":433},[389,1928,1929,1932,1934,1936,1938,1940,1942,1944,1946,1948,1951,1954,1957,1960],{"class":391,"line":1200},[389,1930,1931],{"class":433},"        frames[key] ",[389,1933,506],{"class":429},[389,1935,1221],{"class":433},[389,1937,124],{"class":453},[389,1939,912],{"class":433},[389,1941,915],{"class":522},[389,1943,506],{"class":429},[389,1945,1018],{"class":433},[389,1947,47],{"class":453},[389,1949,1950],{"class":433},"]) ",[389,1952,1953],{"class":429},"if",[389,1955,1956],{"class":433}," has_header ",[389,1958,1959],{"class":429},"else",[389,1961,1244],{"class":433},[389,1963,1964,1966],{"class":391,"line":1206},[389,1965,1309],{"class":429},[389,1967,1138],{"class":433},[389,1969,1970],{"class":391,"line":1215},[389,1971,1972],{"class":433},"    wb.close()\n",[389,1974,1975,1977,1980,1982,1985,1987],{"class":391,"line":1238},[389,1976,454],{"class":453},[389,1978,1979],{"class":433},"({k: v.shape ",[389,1981,879],{"class":429},[389,1983,1984],{"class":433}," k, v ",[389,1986,885],{"class":429},[389,1988,1989],{"class":433}," frames.items()})\n",[10,1991,1992],{},"Keeping the addresses in one dictionary — or in the job's configuration file — also documents the workbook's layout in a single place, so the next change to the sheet means editing one line rather than hunting through the code.",[375,1994,1996],{"id":1995},"prefer-names-over-addresses-when-you-can","Prefer names over addresses when you can",[10,1998,1999,2000,2004,2005,2008],{},"Addresses break when someone inserts a row above the table. If you have any influence over the workbook, ask for the block to be an Excel table (Insert → Table) or a named range. Both move with the data, and both can be read by name — ",[19,2001,2003],{"href":2002},"\u002Fformatting-and-charting-excel-reports-with-python\u002Fcreating-excel-tables-and-autofilters-with-python\u002Fread-an-excel-table-by-name-into-pandas\u002F","Read an Excel Table by Name into pandas"," covers tables, and a defined name's destinations give you the same range address that ",[14,2006,2007],{},"read_range"," accepts.",[375,2010,2012],{"id":2011},"common-pitfalls","Common pitfalls",[607,2014,2015,2025,2041,2049,2059],{},[610,2016,2017,2024],{},[2018,2019,2020,2021,2023],"strong",{},"Off-by-one ",[14,2022,492],{},"."," It counts data rows, not including the header. Compute it as last row minus header row.",[610,2026,2027,2032,2033,2036,2037,2040],{},[2018,2028,2029,2031],{},[14,2030,488],{}," as a row number."," ",[14,2034,2035],{},"skiprows=3"," skips ",[617,2038,2039],{},"three"," rows, making row 4 the header. It is a count, not an address.",[610,2042,2043,2048],{},[2018,2044,2045,2046,2023],{},"Forgetting ",[14,2047,1028],{}," openpyxl returns formula strings otherwise.",[610,2050,2051,2054,2055,2023],{},[2018,2052,2053],{},"Reading a range that includes a total row."," Totals are data to pandas; either stop above them or drop them explicitly, as shown in ",[19,2056,2058],{"href":2057},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fremove-subtotal-and-total-rows-from-an-excel-export\u002F","Remove Subtotal and Total Rows from an Excel Export",[610,2060,2061,2064],{},[2018,2062,2063],{},"Leaving read-only workbooks open."," Close them, or the file stays locked on Windows.",[375,2066,2068],{"id":2067},"performance-notes","Performance notes",[10,2070,2071,2073,2074,2076,2077,2079,2080,2082,2083,2085],{},[14,2072,480],{}," still parses the sheet's rows up to the ones it needs, so on very large sheets ",[14,2075,492],{}," saves memory but not all the reading time. openpyxl in read-only mode with ",[14,2078,936],{}," bounds streams only as far as ",[14,2081,967],{}," and then stops, which makes it the faster choice for a small block near the top of a big sheet. For many ranges from the same file, open the workbook once and read each range from the open sheet rather than calling ",[14,2084,480],{}," repeatedly.",[375,2087,2089],{"id":2088},"conclusion","Conclusion",[10,2091,2092,2093,827,2095,637,2098,2101,2102,2104,2105,2107,2108,2110],{},"To read a block such as B3:F7, either translate the address into ",[14,2094,724],{},[14,2096,2097],{},"skiprows=top - 1",[14,2099,2100],{},"nrows=bottom - top"," for ",[14,2103,480],{},", or pass the A1 string to openpyxl and build the DataFrame from its rows with ",[14,2106,1028],{},". Wrap the openpyxl version in a ",[14,2109,2007],{}," helper for addresses that come from configuration, read to the first blank row when the block grows, and move to tables or named ranges when the layout keeps changing.",[375,2112,2114],{"id":2113},"frequently-asked-questions","Frequently asked questions",[10,2116,2117,2120],{},[2018,2118,2119],{},"How do I translate B3:F20 into read_excel arguments?","\nusecols=\"B:F\" picks the columns. skiprows=2 skips rows 1 and 2 so row 3 becomes the header. nrows=17 reads rows 4 to 20 — nrows counts data rows after the header, so it is the last row minus the header row.",[10,2122,2123,2126],{},[2018,2124,2125],{},"Is openpyxl or pandas better for reading a range?","\npandas is shorter when the range starts with a header row. openpyxl is better when you already have the address as an A1 string, need cell values without a header, or want to read several ranges from one open workbook.",[10,2128,2129,2132],{},[2018,2130,2131],{},"Why do I get formulas instead of numbers with openpyxl?","\nopenpyxl returns formula text unless the workbook is opened with data_only=True. Even then it returns the value cached when the file was last saved by a spreadsheet application; a file written by openpyxl has no cached values.",[10,2134,2135,2138],{},[2018,2136,2137],{},"What if the range moves from month to month?","\nDo not hard-code the address. Find the header row by searching for a known label, read to the first blank row, or have the owner of the sheet turn the block into an Excel table and read it by name.",[375,2140,2142],{"id":2141},"related","Related",[607,2144,2145,2151,2161,2172],{},[610,2146,2147,2148,2150],{},"Up one level: ",[19,2149,22],{"href":21}," — the full set of read_excel options.",[610,2152,2153,2157,2158,2160],{},[19,2154,2156],{"href":2155},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-specific-columns-from-excel-with-pandas\u002F","Read Specific Columns From Excel With Pandas"," — ",[14,2159,484],{}," in every form.",[610,2162,2163,2157,2167,637,2169,2171],{},[19,2164,2166],{"href":2165},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-only-some-rows-of-an-excel-file-with-pandas\u002F","Read Only Some Rows of an Excel File with pandas",[14,2168,488],{},[14,2170,492],{}," in depth.",[610,2173,2174,2178],{},[19,2175,2177],{"href":2176},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets\u002Fread-multiple-tables-from-one-excel-sheet\u002F","Read Multiple Tables from One Excel Sheet"," — when a sheet holds several blocks.",[2180,2181,2182],"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 .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":385,"searchDepth":443,"depth":443,"links":2184},[2185,2186,2187,2188,2189,2190,2191,2192,2193,2194,2195,2196,2197],{"id":377,"depth":443,"text":378},{"id":416,"depth":443,"text":417},{"id":474,"depth":443,"text":475},{"id":782,"depth":443,"text":783},{"id":1045,"depth":443,"text":1046},{"id":1313,"depth":443,"text":1314},{"id":1752,"depth":443,"text":1753},{"id":1995,"depth":443,"text":1996},{"id":2011,"depth":443,"text":2012},{"id":2067,"depth":443,"text":2068},{"id":2088,"depth":443,"text":2089},{"id":2113,"depth":443,"text":2114},{"id":2141,"depth":443,"text":2142},"2026-09-25","Pull exactly one block of cells out of a worksheet — a table that starts at B3 and ends at F20, with other content around it. Do it with read_excel's usecols, skiprows and nrows, or with openpyxl and an A1 range string, and turn it into one reusable function.","md",[2202,2204,2206,2208],{"q":2119,"a":2203},"usecols=\"B:F\" picks the columns. skiprows=2 skips rows 1 and 2 so row 3 becomes the header. nrows=17 reads rows 4 to 20 — nrows counts data rows after the header, so it is the last row minus the header row.",{"q":2125,"a":2205},"pandas is shorter when the range starts with a header row. openpyxl is better when you already have the address as an A1 string, need cell values without a header, or want to read several ranges from one open workbook.",{"q":2131,"a":2207},"openpyxl returns formula text unless the workbook is opened with data_only=True. Even then it returns the value cached when the file was last saved by a spreadsheet application; a file written by openpyxl has no cached values.",{"q":2137,"a":2209},"Do not hard-code the address. Find the header row by searching for a known label, read to the first blank row, or have the owner of the sheet turn the block into an Excel table and read it by name.","read a cell range like b3:f20 into a pandas dataframe",null,{"breadcrumb":2213},[2214,2216,2219],{"name":2215,"item":1306},"Home",{"name":2217,"item":2218},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":2220,"item":21},"Reading Excel Files with Pandas","\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-cell-range-into-a-pandas-dataframe",{"title":2223,"description":2224},"Read a Specific Range (e.g. B3:F20) from Excel into pandas","Read an Excel cell range into a DataFrame: translate B3:F20 into usecols, skiprows and nrows for read_excel, or read ws[\"B3:F20\"] with openpyxl, with a read_range helper and the off-by-one traps.","read-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",[2228,1687,2229],"reading-excel","pandas","how-to","77SPJFWQ4kVn9F0QT8jH3k77rj7MjYBL4hmehOEplLI",[2233,2237],{"title":2234,"path":2235,"stem":2236,"children":-1},"List Sheet Names and Column Headers Without Loading the Data","\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Flist-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",{"title":2238,"path":2239,"stem":2240,"children":-1},"Read a Named Range into pandas","\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-named-range-into-pandas","getting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas\u002Fread-a-named-range-into-pandas\u002Findex",[2242,2244],{"path":2243,"title":2217},"\u002Fgetting-started-with-python-excel-automation",{"path":2245,"title":2220},"\u002Fgetting-started-with-python-excel-automation\u002Freading-excel-files-with-pandas",[],[2248,2251,2254,2257,2260,2263],{"path":2249,"title":2250,"kind":2230},"\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":2252,"title":2253,"kind":2230},"\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":2255,"title":2256,"kind":2230},"\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":2258,"title":2259,"kind":2230},"\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":2261,"title":2262,"kind":2230},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fstandardise-excel-column-names-with-pandas","Standardise Excel Column Names with pandas",{"path":2264,"title":2265,"kind":2266},"\u002Fadvanced-data-transformation-and-cleaning\u002Fextracting-data-from-messy-excel-sheets","Extracting Data from Messy Excel Sheets","guide",1790972065096]