[{"data":1,"prerenderedAt":1463},["ShallowReactive",2],{"doc:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python":3,"surround:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python":1430,"ancestors:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python":1439,"children:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python":1444,"related:\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python":1445},{"id":4,"title":5,"body":6,"dateModified":1398,"datePublished":1398,"description":1399,"extension":1400,"faq":1401,"keyword":1410,"kind":1411,"meta":1412,"navigation":132,"path":1420,"seo":1421,"slug":1424,"stem":1425,"topics":1426,"type":1428,"__hash__":1429},"docs\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python\u002Findex.md","Automate Excel on macOS with Python",{"type":7,"value":8,"toc":1385},"minimark",[9,32,37,68,83,87,90,254,270,436,440,443,637,650,654,657,683,694,770,774,792,915,941,1073,1077,1084,1213,1231,1235,1254,1258,1307,1311,1320,1324,1330,1336,1342,1348,1352,1381],[10,11,12,13,17,18,21,22,25,26,31],"p",{},"Most Excel automation advice assumes Windows: ",[14,15,16],"code",{},"win32com.client.Dispatch(\"Excel.Application\")",", VBA-style COM calls, Task Scheduler. On a Mac none of that exists — there is no COM, and ",[14,19,20],{},"pywin32"," will not install. Excel for Mac can still be automated from Python, but the route depends on what the job really needs. Often it needs no Excel at all: reading, writing and formatting ",[14,23,24],{},".xlsx"," files works identically on every platform with pandas and openpyxl. When Excel itself must do something — recalculate a model, refresh a query, export with its own renderer — xlwings drives Excel for Mac through Apple's scripting bridge, and plain AppleScript fills the gaps. This page sorts out which to use and covers the macOS-specific hurdles: privacy permissions, the sandbox, and scheduling. It belongs to ",[27,28,30],"a",{"href":29},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002F","Automating Excel with COM and pywin32",", whose Windows techniques this page translates.",[33,34,36],"h2",{"id":35},"prerequisites","Prerequisites",[38,39,44],"pre",{"className":40,"code":41,"language":42,"meta":43,"style":43},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install xlwings openpyxl pandas\n","bash","",[14,45,46],{"__ignoreMap":43},[47,48,51,55,59,62,65],"span",{"class":49,"line":50},"line",1,[47,52,54],{"class":53},"sMTad","pip",[47,56,58],{"class":57},"srMev"," install",[47,60,61],{"class":57}," xlwings",[47,63,64],{"class":57}," openpyxl",[47,66,67],{"class":57}," pandas\n",[10,69,70,71,74,75,78,79,82],{},"Steps that control Excel need Excel for Mac (Microsoft 365) and are marked as not run, because our build runs on Linux; the file-based step runs anywhere. Examples use a workbook ",[14,72,73],{},"forecast_model.xlsx"," in your home folder, with an ",[14,76,77],{},"Inputs"," sheet and formulas on a ",[14,80,81],{},"Model"," sheet.",[33,84,86],{"id":85},"step-1-decide-whether-you-need-excel-at-all","Step 1 — Decide whether you need Excel at all",[10,88,89],{},"The single biggest simplification on a Mac is noticing that the job is file work:",[38,91,95],{"className":92,"code":93,"language":94,"meta":43,"style":43},"language-python shiki shiki-themes github-light github-dark-high-contrast","import pandas as pd\nfrom openpyxl import Workbook\n\nwb = Workbook()\nws = wb.active\nws.title = \"Inputs\"\nws.append([\"Assumption\", \"Value\"])\nws.append([\"Growth\", 0.04])\nws.append([\"Price\", 89.0])\nwb.save(\"forecast_model.xlsx\")\nprint(pd.read_excel(\"forecast_model.xlsx\", sheet_name=\"Inputs\"))\n","python",[14,96,97,113,127,134,146,157,168,186,202,217,229],{"__ignoreMap":43},[47,98,99,103,107,110],{"class":49,"line":50},[47,100,102],{"class":101},"s-kum","import",[47,104,106],{"class":105},"skGVy"," pandas ",[47,108,109],{"class":101},"as",[47,111,112],{"class":105}," pd\n",[47,114,116,119,122,124],{"class":49,"line":115},2,[47,117,118],{"class":101},"from",[47,120,121],{"class":105}," openpyxl ",[47,123,102],{"class":101},[47,125,126],{"class":105}," Workbook\n",[47,128,130],{"class":49,"line":129},3,[47,131,133],{"emptyLinePlaceholder":132},true,"\n",[47,135,137,140,143],{"class":49,"line":136},4,[47,138,139],{"class":105},"wb ",[47,141,142],{"class":101},"=",[47,144,145],{"class":105}," Workbook()\n",[47,147,149,152,154],{"class":49,"line":148},5,[47,150,151],{"class":105},"ws ",[47,153,142],{"class":101},[47,155,156],{"class":105}," wb.active\n",[47,158,160,163,165],{"class":49,"line":159},6,[47,161,162],{"class":105},"ws.title ",[47,164,142],{"class":101},[47,166,167],{"class":57}," \"Inputs\"\n",[47,169,171,174,177,180,183],{"class":49,"line":170},7,[47,172,173],{"class":105},"ws.append([",[47,175,176],{"class":57},"\"Assumption\"",[47,178,179],{"class":105},", ",[47,181,182],{"class":57},"\"Value\"",[47,184,185],{"class":105},"])\n",[47,187,189,191,194,196,200],{"class":49,"line":188},8,[47,190,173],{"class":105},[47,192,193],{"class":57},"\"Growth\"",[47,195,179],{"class":105},[47,197,199],{"class":198},"sP0c6","0.04",[47,201,185],{"class":105},[47,203,205,207,210,212,215],{"class":49,"line":204},9,[47,206,173],{"class":105},[47,208,209],{"class":57},"\"Price\"",[47,211,179],{"class":105},[47,213,214],{"class":198},"89.0",[47,216,185],{"class":105},[47,218,220,223,226],{"class":49,"line":219},10,[47,221,222],{"class":105},"wb.save(",[47,224,225],{"class":57},"\"forecast_model.xlsx\"",[47,227,228],{"class":105},")\n",[47,230,232,235,238,240,242,246,248,251],{"class":49,"line":231},11,[47,233,234],{"class":198},"print",[47,236,237],{"class":105},"(pd.read_excel(",[47,239,225],{"class":57},[47,241,179],{"class":105},[47,243,245],{"class":244},"sa561","sheet_name",[47,247,142],{"class":101},[47,249,250],{"class":57},"\"Inputs\"",[47,252,253],{"class":105},"))\n",[10,255,256,257,259,260,264,265,269],{},"pandas and openpyxl read and write ",[14,258,24],{}," files without Excel, on macOS exactly as on Windows or a Linux server — formatting, formulas, charts, tables and protection included. If a task is \"produce a formatted report\" or \"read last month's numbers\", this is the whole answer, and it is also the only answer that keeps working when the script moves to a server. Excel becomes necessary only when something must be ",[261,262,263],"em",{},"calculated or rendered by Excel",": formulas evaluated with Excel's engine, data connections refreshed, Excel's own PDF output. The library choice is covered in ",[27,266,268],{"href":267},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002F","Choosing a Python Excel Library",".",[271,272,280,281,280,285,280,289,280,297,280,307,280,318,280,324,280,328,280,332,280,335,280,340,280,349,280,354,280,361,280,368,280,373,280,378,280,380,280,383,280,387,280,390,280,393,280,399,280,402,280,405,280,407,280,410,280,414,280,417,280,422,280,429,280,433],"svg",{"viewBox":273,"role":274,"ariaLabelledBy":275,"xmlns":278,"style":279},"4 0 752 272","img",[276,277],"mac-route-t","mac-route-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[282,283,284],"title",{"id":276},"Which tool for Excel work on a Mac",[286,287,288],"desc",{"id":277},"If the job only reads or writes files, use pandas and openpyxl, which need no Excel. If Excel must calculate, refresh or render, use xlwings to drive Excel for Mac. For the occasional command xlwings does not expose, call AppleScript with osascript.",[290,291],"rect",{"x":292,"y":293,"width":294,"height":295,"fill":296},"4","0","752","272","#ffffff",[290,298],{"x":299,"y":300,"width":301,"height":302,"rx":303,"fill":304,"stroke":305,"style":306},"225.9","16.0","308.1","75.5","12","#f0f4ff","var(--brand,#5b5cf0)","stroke-width:2px",[308,309,311],"g",{"transform":310},"translate(368.0,29.0) scale(1.000)",[312,313],"path",{"d":314,"fill":315,"stroke":316,"style":317},"M11 4a7 7 0 1 0 .01 0z M16 16l5 5","none","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[319,320,323],"text",{"x":321,"y":302,"style":322},"380.0","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","What does the job need from Excel?",[49,325],{"x1":321,"y1":326,"x2":321,"y2":327,"stroke":305,"style":306},"91.5","111.5",[49,329],{"x1":330,"y1":327,"x2":331,"y2":327,"stroke":305,"style":306},"134.7","625.3",[49,333],{"x1":330,"y1":327,"x2":330,"y2":334,"stroke":305,"style":306},"157.5",[336,337],"polygon",{"points":338,"fill":339},"134.7,161.5 129.7,152.5 139.7,152.5","#5b5cf0",[290,341],{"x":342,"y":343,"width":344,"height":345,"rx":346,"fill":296,"stroke":347,"style":348},"93.0","121.5","83.4","21.0","10","var(--line,#cdd5e6)","stroke-width:1.2px",[319,350,353],{"x":330,"y":351,"style":352},"136.0","font-size:11.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","just the file",[290,355],{"x":356,"y":357,"width":358,"height":342,"rx":303,"fill":359,"stroke":360,"style":306},"20.0","163.5","229.3","#d9f4f1","var(--teal,#0f9488)",[308,362,364],{"transform":363},"translate(122.7,176.5) scale(1.000)",[312,365],{"d":366,"fill":315,"stroke":367,"style":317},"M12 3c-4 0-4 1.6-4 3v2h4.2v1H6c-2 0-3 1.4-3 4s1 4 3 4h2v-2.6c0-1.6 1.3-2.9 2.9-2.9h4.2c1.3 0 2.4-1.1 2.4-2.4V6c0-1.6-1.8-3-5.5-3z M10 5.5h.01 M12 21c4 0 4-1.6 4-3v-2h-4.2v-1H18c2 0 3-1.4 3-4s-1-4-3-4h-2v2.6c0 1.6-1.3 2.9-2.9 2.9H8.9c-1.3 0-2.4 1.1-2.4 2.4V18c0 1.6 1.8 3 5.5 3z M14 18.5h.01","var(--teal-ink,#0b6157)",[319,369,372],{"x":330,"y":370,"style":371},"223.0","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","pandas + openpyxl",[319,374,377],{"x":330,"y":375,"style":376},"242.5","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","no Excel, any OS",[49,379],{"x1":321,"y1":327,"x2":321,"y2":334,"stroke":305,"style":306},[336,381],{"points":382,"fill":339},"380.0,161.5 375.0,152.5 385.0,152.5",[290,384],{"x":385,"y":343,"width":386,"height":345,"rx":346,"fill":296,"stroke":347,"style":348},"328.0","104.0",[319,388,389],{"x":321,"y":351,"style":352},"Excel's engine",[290,391],{"x":392,"y":357,"width":358,"height":342,"rx":303,"fill":304,"stroke":305,"style":306},"265.3",[308,394,396],{"transform":395},"translate(368.0,176.5) scale(1.000)",[312,397],{"d":398,"fill":315,"stroke":316,"style":317},"M6 3h9l4 4v14H6z M15 3v4h4 M9.5 11.5l4.5 6 M14 11.5l-4.5 6",[319,400,401],{"x":321,"y":370,"style":322},"xlwings",[319,403,404],{"x":321,"y":375,"style":376},"drives Excel for Mac",[49,406],{"x1":331,"y1":327,"x2":331,"y2":334,"stroke":305,"style":306},[336,408],{"points":409,"fill":339},"625.3,161.5 620.3,152.5 630.3,152.5",[290,411],{"x":412,"y":343,"width":413,"height":345,"rx":346,"fill":296,"stroke":347,"style":348},"549.9","150.8",[319,415,416],{"x":331,"y":351,"style":352},"one missing command",[290,418],{"x":419,"y":357,"width":358,"height":342,"rx":303,"fill":420,"stroke":421,"style":306},"510.7","#fdefd8","var(--gold,#b4740a)",[308,423,425],{"transform":424},"translate(613.3,176.5) scale(1.000)",[312,426],{"d":427,"fill":315,"stroke":428,"style":317},"M4 5h16v14H4z M7 9l3 3-3 3 M12 15h5","var(--gold-ink,#7a4e06)",[319,430,432],{"x":331,"y":370,"style":431},"font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","AppleScript via osascript",[319,434,435],{"x":331,"y":375,"style":376},"Excel's scripting dictionary",[33,437,439],{"id":438},"step-2-drive-excel-for-mac-with-xlwings","Step 2 — Drive Excel for Mac with xlwings",[10,441,442],{},"xlwings uses the same Python API on macOS and Windows; only its plumbing differs:",[38,444,446],{"className":92,"code":445,"language":94,"meta":43,"style":43},"import xlwings as xw\nfrom pathlib import Path\n\npath = Path.home() \u002F \"forecast_model.xlsx\"\napp = xw.App(visible=False)\ntry:\n    wb = app.books.open(str(path))\n    wb.sheets[\"Inputs\"][\"B2\"].value = 0.05          # change an input\n    app.calculate()                                  # let Excel recalculate\n    result = wb.sheets[\"Model\"][\"B10\"].value\n    print(\"forecast with 5% growth:\", result)\n    wb.save()\n    wb.close()\nfinally:\n    app.quit()\n",[14,447,448,460,472,476,492,512,520,536,561,569,590,611,617,623,631],{"__ignoreMap":43},[47,449,450,452,455,457],{"class":49,"line":50},[47,451,102],{"class":101},[47,453,454],{"class":105}," xlwings ",[47,456,109],{"class":101},[47,458,459],{"class":105}," xw\n",[47,461,462,464,467,469],{"class":49,"line":115},[47,463,118],{"class":101},[47,465,466],{"class":105}," pathlib ",[47,468,102],{"class":101},[47,470,471],{"class":105}," Path\n",[47,473,474],{"class":49,"line":129},[47,475,133],{"emptyLinePlaceholder":132},[47,477,478,481,483,486,489],{"class":49,"line":136},[47,479,480],{"class":105},"path ",[47,482,142],{"class":101},[47,484,485],{"class":105}," Path.home() ",[47,487,488],{"class":101},"\u002F",[47,490,491],{"class":57}," \"forecast_model.xlsx\"\n",[47,493,494,497,499,502,505,507,510],{"class":49,"line":148},[47,495,496],{"class":105},"app ",[47,498,142],{"class":101},[47,500,501],{"class":105}," xw.App(",[47,503,504],{"class":244},"visible",[47,506,142],{"class":101},[47,508,509],{"class":198},"False",[47,511,228],{"class":105},[47,513,514,517],{"class":49,"line":159},[47,515,516],{"class":101},"try",[47,518,519],{"class":105},":\n",[47,521,522,525,527,530,533],{"class":49,"line":170},[47,523,524],{"class":105},"    wb ",[47,526,142],{"class":101},[47,528,529],{"class":105}," app.books.open(",[47,531,532],{"class":198},"str",[47,534,535],{"class":105},"(path))\n",[47,537,538,541,543,546,549,552,554,557],{"class":49,"line":188},[47,539,540],{"class":105},"    wb.sheets[",[47,542,250],{"class":57},[47,544,545],{"class":105},"][",[47,547,548],{"class":57},"\"B2\"",[47,550,551],{"class":105},"].value ",[47,553,142],{"class":101},[47,555,556],{"class":198}," 0.05",[47,558,560],{"class":559},"s-wDw","          # change an input\n",[47,562,563,566],{"class":49,"line":204},[47,564,565],{"class":105},"    app.calculate()                                  ",[47,567,568],{"class":559},"# let Excel recalculate\n",[47,570,571,574,576,579,582,584,587],{"class":49,"line":219},[47,572,573],{"class":105},"    result ",[47,575,142],{"class":101},[47,577,578],{"class":105}," wb.sheets[",[47,580,581],{"class":57},"\"Model\"",[47,583,545],{"class":105},[47,585,586],{"class":57},"\"B10\"",[47,588,589],{"class":105},"].value\n",[47,591,592,595,598,601,605,608],{"class":49,"line":231},[47,593,594],{"class":198},"    print",[47,596,597],{"class":105},"(",[47,599,600],{"class":57},"\"forecast with 5",[47,602,604],{"class":603},"sSjpA","% g",[47,606,607],{"class":57},"rowth:\"",[47,609,610],{"class":105},", result)\n",[47,612,614],{"class":49,"line":613},12,[47,615,616],{"class":105},"    wb.save()\n",[47,618,620],{"class":49,"line":619},13,[47,621,622],{"class":105},"    wb.close()\n",[47,624,626,629],{"class":49,"line":625},14,[47,627,628],{"class":101},"finally",[47,630,519],{"class":105},[47,632,634],{"class":49,"line":633},15,[47,635,636],{"class":105},"    app.quit()\n",[10,638,639,640,644,645,488,647,649],{},"Opening, writing values, recalculating, reading results and saving look exactly like the Windows examples in ",[27,641,643],{"href":642},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fread-and-write-a-live-excel-workbook-with-xlwings\u002F","Read and Write a Live Excel Workbook with xlwings",". That portability is the main reason to prefer xlwings over raw AppleScript. The ",[14,646,516],{},[14,648,628],{}," matters as much on a Mac as on Windows: a script that crashes halfway otherwise leaves an invisible Excel running.",[33,651,653],{"id":652},"step-3-the-first-run-permission-prompts","Step 3 — The first-run permission prompts",[10,655,656],{},"The first time a Python process controls Excel, macOS asks the user whether Terminal (or your editor, or whichever app launched Python) may control Microsoft Excel. This is macOS's Automation privacy protection:",[658,659,660,673,680],"ul",{},[661,662,663,664,668,669,672],"li",{},"Click ",[665,666,667],"strong",{},"OK"," to allow it; the choice is stored under ",[261,670,671],{},"System Settings › Privacy & Security › Automation",", where it can be changed later.",[661,674,675,676,679],{},"If you clicked ",[261,677,678],{},"Don't Allow",", scripts fail with an error mentioning that the application is not allowed to send Apple events; enable the checkbox for Excel under the launching app in that settings page.",[661,681,682],{},"A scheduled job runs under a different parent process than your Terminal, so it may need its own approval — run it once interactively to trigger the prompt.",[10,684,685,686,689,690,693],{},"Excel for Mac is also ",[261,687,688],{},"sandboxed",": it can only open files in places it has been granted access to. When a script opens a file in a new folder, Excel may show a ",[665,691,692],{},"Grant File Access"," dialog and wait. For unattended jobs, keep workbooks in a folder Excel already has access to (opening one file there by hand and granting access usually suffices), so no dialog can block the run.",[271,695,280,700,280,703,280,706,280,709,280,712,280,718,280,722,280,726,280,731,280,734,280,737,280,742,280,744,280,747,280,751,280,754,280,757,280,763,280,767],{"viewBox":696,"role":274,"ariaLabelledBy":697,"xmlns":278,"style":279},"4 0 752 125",[698,699],"mac-perms-t","mac-perms-d",[282,701,702],{"id":698},"The hurdles before a Mac script can control Excel",[286,704,705],{"id":699},"The first run triggers the Automation permission prompt for the app that launched Python. Opening a file in a new location can trigger Excel's Grant File Access dialog. Once both are approved, scripts and scheduled jobs run without dialogs.",[290,707],{"x":292,"y":293,"width":294,"height":708,"fill":296},"125",[290,710],{"x":356,"y":300,"width":711,"height":342,"rx":303,"fill":420,"stroke":421,"style":306},"216.0",[308,713,715],{"transform":714},"translate(116.0,29.0) scale(1.000)",[312,716],{"d":717,"fill":315,"stroke":428,"style":317},"M6 11h12v9H6z M8.5 11V8a3.5 3.5 0 0 1 7 0v3",[319,719,721],{"x":720,"y":302,"style":431},"128.0","Automation prompt",[319,723,725],{"x":720,"y":724,"style":376},"95.0","allow Terminal to control Excel",[49,727],{"x1":728,"y1":729,"x2":730,"y2":729,"stroke":305,"style":306},"241.0","62.5","263.0",[336,732],{"points":733,"fill":339},"267.0,62.5 258.0,67.5 258.0,57.5",[290,735],{"x":736,"y":300,"width":711,"height":342,"rx":303,"fill":420,"stroke":421,"style":306},"272.0",[308,738,739],{"transform":310},[312,740],{"d":741,"fill":315,"stroke":428,"style":317},"M3 6h6l2 2h10v11H3z",[319,743,692],{"x":321,"y":302,"style":431},[319,745,746],{"x":321,"y":724,"style":376},"Excel sandbox, per folder",[49,748],{"x1":749,"y1":729,"x2":750,"y2":729,"stroke":305,"style":306},"493.0","515.0",[336,752],{"points":753,"fill":339},"519.0,62.5 510.0,67.5 510.0,57.5",[290,755],{"x":756,"y":300,"width":711,"height":342,"rx":303,"fill":359,"stroke":360,"style":306},"524.0",[308,758,760],{"transform":759},"translate(620.0,29.0) scale(1.000)",[312,761],{"d":762,"fill":315,"stroke":367,"style":317},"M5 12.5l4.5 4.5L19 7",[319,764,766],{"x":765,"y":302,"style":371},"632.0","Unattended runs",[319,768,769],{"x":765,"y":724,"style":376},"no dialogs left",[33,771,773],{"id":772},"step-4-the-api-escape-hatch-is-different-on-a-mac","Step 4 — The .api escape hatch is different on a Mac",[10,775,776,777,780,781,784,785,787,788,791],{},"On Windows, ",[14,778,779],{},".api"," returns a COM object and VBA-style code works: ",[14,782,783],{},"rng.api.Font.Bold = True",". On macOS, ",[14,786,779],{}," returns an ",[14,789,790],{},"appscript"," reference to Excel's AppleScript object model, which uses different names and call style. The xlwings properties hide that difference, so use them wherever they exist:",[38,793,795],{"className":92,"code":794,"language":94,"meta":43,"style":43},"rng = wb.sheets[\"Model\"][\"A1:D1\"]\nrng.font.bold = True                 # works on both platforms\nrng.color = \"#E0E7FF\"                # works on both platforms\nrng.number_format = \"#,##0.00\"       # works on both platforms\n\nimport sys\nif sys.platform == \"darwin\":\n    rng.api.font_object.bold.set(True)            # appscript style (macOS)\nelse:\n    rng.api.Font.Bold = True                      # COM style (Windows)\n",[14,796,797,816,829,842,855,859,866,882,896,903],{"__ignoreMap":43},[47,798,799,802,804,806,808,810,813],{"class":49,"line":50},[47,800,801],{"class":105},"rng ",[47,803,142],{"class":101},[47,805,578],{"class":105},[47,807,581],{"class":57},[47,809,545],{"class":105},[47,811,812],{"class":57},"\"A1:D1\"",[47,814,815],{"class":105},"]\n",[47,817,818,821,823,826],{"class":49,"line":115},[47,819,820],{"class":105},"rng.font.bold ",[47,822,142],{"class":101},[47,824,825],{"class":198}," True",[47,827,828],{"class":559},"                 # works on both platforms\n",[47,830,831,834,836,839],{"class":49,"line":129},[47,832,833],{"class":105},"rng.color ",[47,835,142],{"class":101},[47,837,838],{"class":57}," \"#E0E7FF\"",[47,840,841],{"class":559},"                # works on both platforms\n",[47,843,844,847,849,852],{"class":49,"line":136},[47,845,846],{"class":105},"rng.number_format ",[47,848,142],{"class":101},[47,850,851],{"class":57}," \"#,##0.00\"",[47,853,854],{"class":559},"       # works on both platforms\n",[47,856,857],{"class":49,"line":148},[47,858,133],{"emptyLinePlaceholder":132},[47,860,861,863],{"class":49,"line":159},[47,862,102],{"class":101},[47,864,865],{"class":105}," sys\n",[47,867,868,871,874,877,880],{"class":49,"line":170},[47,869,870],{"class":101},"if",[47,872,873],{"class":105}," sys.platform ",[47,875,876],{"class":101},"==",[47,878,879],{"class":57}," \"darwin\"",[47,881,519],{"class":105},[47,883,884,887,890,893],{"class":49,"line":188},[47,885,886],{"class":105},"    rng.api.font_object.bold.set(",[47,888,889],{"class":198},"True",[47,891,892],{"class":105},")            ",[47,894,895],{"class":559},"# appscript style (macOS)\n",[47,897,898,901],{"class":49,"line":204},[47,899,900],{"class":101},"else",[47,902,519],{"class":105},[47,904,905,908,910,912],{"class":49,"line":219},[47,906,907],{"class":105},"    rng.api.Font.Bold ",[47,909,142],{"class":101},[47,911,825],{"class":198},[47,913,914],{"class":559},"                      # COM style (Windows)\n",[10,916,917,918,921,922,925,926,929,930,933,934,936,937,269],{},"The macOS line is the same call xlwings itself makes internally for ",[14,919,920],{},"font.bold"," — a property read with ",[14,923,924],{},".get()"," and written with ",[14,927,928],{},".set()"," on the range's ",[14,931,932],{},"font_object",". The rule of thumb: write against xlwings' own API, and keep any ",[14,935,779],{}," calls in a small, clearly marked platform branch. Code translated from a recorded VBA macro will almost always be the Windows form. The general formatting properties are listed in ",[27,938,940],{"href":939},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-xlwings-basics\u002Fformat-cells-in-a-live-workbook-with-xlwings\u002F","Format Cells in a Live Workbook with xlwings",[271,942,280,947,280,950,280,953,280,956,280,961,280,968,280,974,280,980,280,986,280,992,280,996,280,1001,280,1005,280,1010,280,1014,280,1020,280,1023,280,1029,280,1034,280,1038,280,1042,280,1049,280,1052,280,1057,280,1060,280,1065,280,1068],{"viewBox":943,"role":274,"ariaLabelledBy":944,"xmlns":278,"style":279},"4 0 752 233",[945,946],"mac-vs-win-t","mac-vs-win-d",[282,948,949],{"id":945},"Excel automation on Windows and macOS",[286,951,952],{"id":946},"Windows offers COM through pywin32 and xlwings, with .api exposing COM objects and Task Scheduler for jobs. macOS has no COM; xlwings works through AppleScript, .api exposes appscript references with different syntax, AppleScript can be called with osascript, permissions and the sandbox must be approved, and launchd schedules jobs.",[290,954],{"x":292,"y":293,"width":294,"height":955,"fill":296},"233",[290,957],{"x":356,"y":300,"width":958,"height":959,"rx":960,"fill":304,"stroke":305,"style":306},"351.0","201.0","14",[308,962,964],{"transform":963},"translate(182.5,29.0) scale(1.083)",[312,965],{"d":966,"fill":315,"stroke":316,"style":967},"M3 5.5l8-1.2v7.2H3z M13 4l8-1.2v8.7h-8z M3 13.5h8v7.2l-8-1.2z M13 13.5h8v8.7l-8-1.2z","stroke-width:1.66px;stroke-linecap:round;stroke-linejoin:round",[319,969,973],{"x":970,"y":971,"style":972},"195.5","78.0","font-size:14px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle","Windows",[49,975],{"x1":976,"y1":977,"x2":978,"y2":977,"stroke":305,"style":979},"36.0","91.0","355.0","stroke-width:1px",[319,981,985],{"x":982,"y":983,"style":984},"60.0","111.0","font-size:12px;font-weight:400;fill:var(--text,#172033);text-anchor:start","pywin32 \u002F COM available",[308,987,989],{"transform":988},"translate(38.5,99.5) scale(0.625)",[312,990],{"d":762,"fill":315,"stroke":360,"style":991},"stroke-width:2.88px;stroke-linecap:round;stroke-linejoin:round",[319,993,995],{"x":982,"y":994,"style":984},"137.0","xlwings .api = COM objects",[308,997,999],{"transform":998},"translate(38.5,125.5) scale(0.625)",[312,1000],{"d":762,"fill":315,"stroke":360,"style":991},[319,1002,1004],{"x":982,"y":1003,"style":984},"163.0","VBA-style code translates directly",[308,1006,1008],{"transform":1007},"translate(38.5,151.5) scale(0.625)",[312,1009],{"d":762,"fill":315,"stroke":360,"style":991},[319,1011,1013],{"x":982,"y":1012,"style":984},"189.0","Task Scheduler for jobs",[308,1015,1017],{"transform":1016},"translate(38.5,177.5) scale(0.625)",[312,1018],{"d":1019,"fill":315,"stroke":421,"style":991},"M12 3.5l9.5 17h-19z M12 10v5 M12 17.8v.4",[290,1021],{"x":1022,"y":300,"width":958,"height":959,"rx":960,"fill":359,"stroke":360,"style":306},"389.0",[308,1024,1026],{"transform":1025},"translate(551.5,29.0) scale(1.083)",[312,1027],{"d":1028,"fill":315,"stroke":367,"style":967},"M12 9a3 3 0 1 0 .01 0z M12 2.5v3 M12 18.5v3 M2.5 12h3 M18.5 12h3 M5.3 5.3l2.1 2.1 M16.6 16.6l2.1 2.1 M5.3 18.7l2.1-2.1 M16.6 7.4l2.1-2.1",[319,1030,1033],{"x":1031,"y":971,"style":1032},"564.5","font-size:14px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","macOS",[49,1035],{"x1":1036,"y1":977,"x2":1037,"y2":977,"stroke":360,"style":979},"405.0","724.0",[319,1039,1041],{"x":1040,"y":983,"style":984},"429.0","no COM, no pywin32",[308,1043,1045],{"transform":1044},"translate(407.5,99.5) scale(0.625)",[312,1046],{"d":1047,"fill":315,"stroke":1048,"style":991},"M6 6l12 12 M18 6L6 18","var(--accent,#f43f8f)",[319,1050,1051],{"x":1040,"y":994,"style":984},"xlwings works the same at its own API level",[308,1053,1055],{"transform":1054},"translate(407.5,125.5) scale(0.625)",[312,1056],{"d":762,"fill":315,"stroke":360,"style":991},[319,1058,1059],{"x":1040,"y":1003,"style":984},".api = appscript, different syntax",[308,1061,1063],{"transform":1062},"translate(407.5,151.5) scale(0.625)",[312,1064],{"d":1019,"fill":315,"stroke":421,"style":991},[319,1066,1067],{"x":1040,"y":1012,"style":984},"privacy prompts, sandbox, launchd",[308,1069,1071],{"transform":1070},"translate(407.5,177.5) scale(0.625)",[312,1072],{"d":1019,"fill":315,"stroke":421,"style":991},[33,1074,1076],{"id":1075},"step-5-applescript-from-python-for-the-gaps","Step 5 — AppleScript from Python for the gaps",[10,1078,1079,1080,1083],{},"For a one-off command that neither xlwings nor openpyxl covers, Excel's AppleScript dictionary is available through the ",[14,1081,1082],{},"osascript"," command-line tool:",[38,1085,1087],{"className":92,"code":1086,"language":94,"meta":43,"style":43},"import subprocess\n\nscript = f'''\ntell application \"Microsoft Excel\"\n    open POSIX file \"{path}\"\n    calculate full\n    save active workbook\n    close active workbook saving no\nend tell\n'''\nresult = subprocess.run([\"osascript\", \"-e\", script], capture_output=True, text=True, timeout=120)\nprint(result.returncode, result.stdout.strip(), result.stderr.strip())\n",[14,1088,1089,1096,1100,1113,1118,1134,1139,1144,1149,1154,1158,1206],{"__ignoreMap":43},[47,1090,1091,1093],{"class":49,"line":50},[47,1092,102],{"class":101},[47,1094,1095],{"class":105}," subprocess\n",[47,1097,1098],{"class":49,"line":115},[47,1099,133],{"emptyLinePlaceholder":132},[47,1101,1102,1105,1107,1110],{"class":49,"line":129},[47,1103,1104],{"class":105},"script ",[47,1106,142],{"class":101},[47,1108,1109],{"class":101}," f",[47,1111,1112],{"class":57},"'''\n",[47,1114,1115],{"class":49,"line":136},[47,1116,1117],{"class":57},"tell application \"Microsoft Excel\"\n",[47,1119,1120,1123,1126,1128,1131],{"class":49,"line":148},[47,1121,1122],{"class":57},"    open POSIX file \"",[47,1124,1125],{"class":603},"{",[47,1127,312],{"class":105},[47,1129,1130],{"class":603},"}",[47,1132,1133],{"class":57},"\"\n",[47,1135,1136],{"class":49,"line":159},[47,1137,1138],{"class":57},"    calculate full\n",[47,1140,1141],{"class":49,"line":170},[47,1142,1143],{"class":57},"    save active workbook\n",[47,1145,1146],{"class":49,"line":188},[47,1147,1148],{"class":57},"    close active workbook saving no\n",[47,1150,1151],{"class":49,"line":204},[47,1152,1153],{"class":57},"end tell\n",[47,1155,1156],{"class":49,"line":219},[47,1157,1112],{"class":57},[47,1159,1160,1163,1165,1168,1171,1173,1176,1179,1182,1184,1186,1188,1190,1192,1194,1196,1199,1201,1204],{"class":49,"line":231},[47,1161,1162],{"class":105},"result ",[47,1164,142],{"class":101},[47,1166,1167],{"class":105}," subprocess.run([",[47,1169,1170],{"class":57},"\"osascript\"",[47,1172,179],{"class":105},[47,1174,1175],{"class":57},"\"-e\"",[47,1177,1178],{"class":105},", script], ",[47,1180,1181],{"class":244},"capture_output",[47,1183,142],{"class":101},[47,1185,889],{"class":198},[47,1187,179],{"class":105},[47,1189,319],{"class":244},[47,1191,142],{"class":101},[47,1193,889],{"class":198},[47,1195,179],{"class":105},[47,1197,1198],{"class":244},"timeout",[47,1200,142],{"class":101},[47,1202,1203],{"class":198},"120",[47,1205,228],{"class":105},[47,1207,1208,1210],{"class":49,"line":613},[47,1209,234],{"class":198},[47,1211,1212],{"class":105},"(result.returncode, result.stdout.strip(), result.stderr.strip())\n",[10,1214,1215,1218,1219,1222,1223,1226,1227,1230],{},[14,1216,1217],{},"osascript -e"," runs the script and returns its output; check ",[14,1220,1221],{},"returncode"," and ",[14,1224,1225],{},"stderr",", because AppleScript errors (a missing file, a permission refusal) are reported there rather than as Python exceptions. Excel's dictionary — viewable in Script Editor via ",[261,1228,1229],{},"File › Open Dictionary"," — lists every command; build and test scripts there first, then paste them into Python. Keep AppleScript for small gaps: anything substantial is easier to maintain in xlwings, which also runs on Windows.",[33,1232,1234],{"id":1233},"step-6-schedule-it-with-launchd","Step 6 — Schedule it with launchd",[10,1236,1237,1238,1241,1242,1245,1246,1249,1250,269],{},"The Mac equivalent of Task Scheduler or cron is ",[14,1239,1240],{},"launchd",", configured with a small property-list file in ",[14,1243,1244],{},"~\u002FLibrary\u002FLaunchAgents",". Because controlling Excel needs a logged-in user session (Excel is a GUI application), use a ",[261,1247,1248],{},"LaunchAgent",", not a system-wide daemon, and expect the job to run only while that user is logged in. File-only jobs from Step 1 have no such restriction and can run anywhere. The full setup, including the plist and log files, is in ",[27,1251,1253],{"href":1252},"\u002Fautomating-reporting-workflows\u002Fscheduling-python-excel-scripts-with-cron\u002Fschedule-a-python-excel-script-on-macos-with-launchd\u002F","Schedule a Python Excel Script on macOS with launchd",[33,1255,1257],{"id":1256},"common-pitfalls","Common pitfalls",[658,1259,1260,1266,1272,1278,1284,1293],{},[661,1261,1262,1265],{},[665,1263,1264],{},"Installing pywin32 on a Mac."," It is Windows-only; use xlwings or file-based libraries.",[661,1267,1268,1271],{},[665,1269,1270],{},"Using Excel when the file is enough."," openpyxl and pandas need no permissions, no Excel and no logged-in user.",[661,1273,1274,1277],{},[665,1275,1276],{},"Ignoring the permission prompt."," A refused Automation permission makes every script fail until it is re-enabled in System Settings.",[661,1279,1280,1283],{},[665,1281,1282],{},"Files outside Excel's granted folders."," The Grant File Access dialog blocks unattended runs; keep files in an approved folder.",[661,1285,1286,1292],{},[665,1287,1288,1289,1291],{},"Windows ",[14,1290,779],{}," code on a Mac."," COM-style calls fail; stick to xlwings' own API or branch by platform.",[661,1294,1295,1298,1299,1302,1303,1306],{},[665,1296,1297],{},"Hard-coded Windows paths."," ",[14,1300,1301],{},"C:\\Reports\\file.xlsx"," means nothing on a Mac; build paths with ",[14,1304,1305],{},"pathlib.Path",", as in the examples, so the same script runs on both.",[33,1308,1310],{"id":1309},"conclusion","Conclusion",[10,1312,1313,1314,1316,1317,1319],{},"On a Mac, start by asking whether Excel is needed at all — pandas and openpyxl handle file work on every platform. When Excel's engine is required, drive it with xlwings, whose API is the same as on Windows, approve the Automation permission and Excel's file-access prompt once, and keep any ",[14,1315,779],{}," code in a platform-specific branch. Use AppleScript through ",[14,1318,1082],{}," for the rare missing command, and schedule GUI-dependent jobs with a launchd LaunchAgent in a logged-in session.",[33,1321,1323],{"id":1322},"frequently-asked-questions","Frequently asked questions",[10,1325,1326,1329],{},[665,1327,1328],{},"Can I use pywin32 or win32com on a Mac?","\nNo. COM and pywin32 exist only on Windows. On macOS, use xlwings to control Excel, or openpyxl and pandas to work with .xlsx files without Excel.",[10,1331,1332,1335],{},[665,1333,1334],{},"Does xlwings work on macOS?","\nYes. xlwings drives Excel for Mac through Apple's scripting bridge, and its own API — opening books, reading and writing ranges, formatting, calculating — is the same as on Windows. Only code that uses .api differs.",[10,1337,1338,1341],{},[665,1339,1340],{},"Why does my Python script say it is not allowed to send Apple events to Excel?","\nmacOS blocked the Automation permission for the app that launched Python. Enable Microsoft Excel for that app under System Settings, Privacy & Security, Automation, then run the script again.",[10,1343,1344,1347],{},[665,1345,1346],{},"How do I schedule an Excel automation script on a Mac?","\nUse launchd with a LaunchAgent plist in ~\u002FLibrary\u002FLaunchAgents. Jobs that control Excel need the user to be logged in; jobs that only use openpyxl or pandas do not.",[33,1349,1351],{"id":1350},"related","Related",[658,1353,1354,1360,1367,1374],{},[661,1355,1356,1357,1359],{},"Up one level: ",[27,1358,30],{"href":29}," — the Windows side of Excel automation.",[661,1361,1362,1366],{},[27,1363,1365],{"href":1364},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fxlwings-vs-pywin32-for-excel-automation\u002F","xlwings vs pywin32 for Excel Automation"," — why xlwings is the portable choice.",[661,1368,1369,1373],{},[27,1370,1372],{"href":1371},"\u002Fgetting-started-with-python-excel-automation\u002Fhandling-excel-file-formats-and-conversions\u002Fautomate-libreoffice-calc-from-python-with-uno\u002F","Automate LibreOffice Calc from Python with UNO"," — a spreadsheet engine without Excel.",[661,1375,1376,1380],{},[27,1377,1379],{"href":1378},"\u002Fgetting-started-with-python-excel-automation\u002Fchoosing-a-python-excel-library\u002Fpython-vs-office-scripts-for-excel-automation\u002F","Python vs Office Scripts for Excel Automation"," — cloud-side automation that is platform-neutral.",[1382,1383,1384],"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 .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":43,"searchDepth":115,"depth":115,"links":1386},[1387,1388,1389,1390,1391,1392,1393,1394,1395,1396,1397],{"id":35,"depth":115,"text":36},{"id":85,"depth":115,"text":86},{"id":438,"depth":115,"text":439},{"id":652,"depth":115,"text":653},{"id":772,"depth":115,"text":773},{"id":1075,"depth":115,"text":1076},{"id":1233,"depth":115,"text":1234},{"id":1256,"depth":115,"text":1257},{"id":1309,"depth":115,"text":1310},{"id":1322,"depth":115,"text":1323},{"id":1350,"depth":115,"text":1351},"2026-10-02","pywin32 and COM do not exist on a Mac, so automating Excel there takes different tools: openpyxl and pandas when you only need the file, xlwings when Excel itself must do the work, AppleScript through osascript for the odd task xlwings does not cover — plus the macOS permission prompts, the Excel sandbox file-access dialog, and scheduling with launchd.","md",[1402,1404,1406,1408],{"q":1328,"a":1403},"No. COM and pywin32 exist only on Windows. On macOS, use xlwings to control Excel, or openpyxl and pandas to work with .xlsx files without Excel.",{"q":1334,"a":1405},"Yes. xlwings drives Excel for Mac through Apple's scripting bridge, and its own API — opening books, reading and writing ranges, formatting, calculating — is the same as on Windows. Only code that uses .api differs.",{"q":1340,"a":1407},"macOS blocked the Automation permission for the app that launched Python. Enable Microsoft Excel for that app under System Settings, Privacy & Security, Automation, then run the script again.",{"q":1346,"a":1409},"Use launchd with a LaunchAgent plist in ~\u002FLibrary\u002FLaunchAgents. Jobs that control Excel need the user to be logged in; jobs that only use openpyxl or pandas do not.","automate excel on macos with python",null,{"breadcrumb":1413},[1414,1416,1419],{"name":1415,"item":488},"Home",{"name":1417,"item":1418},"Getting Started with Python Excel Automation","\u002Fgetting-started-with-python-excel-automation\u002F",{"name":30,"item":29},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python",{"title":1422,"description":1423},"Automate Excel on macOS with Python (xlwings, AppleScript)","Excel automation on a Mac: when file-based openpyxl is enough, driving Excel with xlwings, running AppleScript from Python with osascript, Automation privacy permissions, the sandbox Grant Access prompt, .api differences from Windows, and launchd scheduling.","automate-excel-on-macos-with-python","getting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fautomate-excel-on-macos-with-python\u002Findex",[1427,401],"com-automation","how-to","-Zc3Hr6SuU5YdQB1zTdoEFBd1J1KSw0Q_V7P7ncziog",[1431,1435],{"title":1432,"path":1433,"stem":1434,"children":-1},"Add a VBA Macro to a Workbook with xlsxwriter","\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fadd-a-vba-macro-to-a-workbook-with-xlsxwriter","getting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fadd-a-vba-macro-to-a-workbook-with-xlsxwriter\u002Findex",{"title":1436,"path":1437,"stem":1438,"children":-1},"Close Excel Cleanly and Avoid Orphan COM Processes","\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fclose-excel-cleanly-and-avoid-orphan-com-processes","getting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fclose-excel-cleanly-and-avoid-orphan-com-processes\u002Findex",[1440,1442],{"path":1441,"title":30},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32",{"path":1443,"title":1417},"\u002Fgetting-started-with-python-excel-automation",[],[1446,1449,1452,1453,1457,1460],{"path":1447,"title":1448,"kind":1428},"\u002Fautomating-reporting-workflows\u002Ftesting-and-packaging-excel-automation-scripts\u002Ftest-win32com-and-xlwings-code-without-excel","Test win32com and xlwings Code Without Excel",{"path":1450,"title":1451,"kind":1428},"\u002Fformatting-and-charting-excel-reports-with-python\u002Finserting-images-and-logos-into-excel\u002Fexport-an-excel-chart-as-an-image","Export an Excel Chart as an Image with Python",{"path":1437,"title":1436,"kind":1428},{"path":1454,"title":1455,"kind":1456},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fhandle-com-errors-and-excel-dialog-prompts-in-python","Handle COM Errors and Excel Dialog Prompts in Python","fix",{"path":1458,"title":1459,"kind":1428},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fprint-an-excel-workbook-from-python-with-win32com","Print an Excel Workbook from Python with win32com",{"path":1461,"title":1462,"kind":1428},"\u002Fgetting-started-with-python-excel-automation\u002Fautomating-excel-with-com-and-pywin32\u002Fread-and-write-cell-ranges-with-win32com","Read and Write Cell Ranges with win32com",1790972055328]