Python - Control/Edit existing window/workbook of Excel - python

I'm working on a little script to automate some data entry. I have two windows open that this same data needs to be entered in every 15 minutes or so. One program I have it entering through GUI manipulation with pywinauto. The other window is an Excel workbook.
My problem is, the workbook is and must be left open (it displays a chart I use and analyze in real-time). I'm wondering how I can go about having my Python script find that specific window (the file name and location is known) without having to open a new instance. I need to edit 4 cells on a specific Worksheet on this Workbook.
Is this possible (to edit/control an existing Workbook that is already open in Windows)?

Yes, it's possible. You can use Workbooks property of Excel.Application object:
import win32com.client
excel = win32com.client.Dispatch('Excel.Application')
for w in excel.Workbooks:
print(w.Name)
You should see "Book1" printed, the name of the new file open. Then run this command:
excel.Workbooks[1].Worksheets[1].Cells[1][1].Value = '444'
You should now see cell A1 have the value of 444.

Related

On Mac, how can I refresh an Excel spreadsheet (especially formula cells) in Python after making and saving changes with openpyxl?

Let's say I have a spreadsheet like this:
10
5
=SUM(A1, A2)
And I have code like this:
import openpyxl
import os
spreadsheet = openpyxl.load_workbook("book.xlsx")
worksheet = spreadsheet.active
worksheet["A2"].value = 7
spreadsheet.save("book.xlsx")
spreadsheet.close()
spreadsheet = openpyxl.load_workbook("book.xlsx")
worksheet = spreadsheet.active
print(worksheet["A3"].value)
The last statement will print None instead of 17 like it should, and I heard it's because formulas aren't computed on spreadsheets written with openpyxl, and right now the only way I can refresh it is by opening it in Excel and pressing CMD S.
I could add these two lines before reopening the spreadsheet with openpyxl, to open the excel spreadsheet automatically in Excel, press CMD S myself then exit, and finally then press enter when I'm done to continue, but a completely automatic solution would be better:
os.system("open 'book.xlsx'")
input("Enter once you've saved the spreadsheet: ")
One thing I found is to use pywin32 but like the name says, it's only for Windows. Is there any library to do it that's cross platform, or at least works on Mac?

Openpyxl-Made changes to excel and store it in a dataframe, how to kill the Excel without saving all the changes and avoid further recovery dialogue?

I need to open and edit my Excel with openpyxl, store the excel as a dataframe, and close the excel without any changes. Are there any ways to kill the excel and disable the auto-recovery dialogue which may pop out later?
The reason I'm asking is that my code worked perfectly fine in Pycharm, however after I packed it into .exe with pyinstaller, the code stopped working, the error said "Excel cannot access the file, there are serval possible reasons, the file name or path does not exist, or the file is being used by another program, or the workbook you are saving has the same name as a currently open workbook.
I assume it is because the openpyxl did not really close the excel, and I exported it to a different folder with the same file name.
Here is my code:
wb1 = openpyxl.load_workbook(my_path, keep_vba=True)
ws1 = wb1["sheet name"]
making changes...
ws1_df = pd.DataFrame(ws1.values)
wb1.close()
Many thanks ahead :)
The following way you can do this. solution
from win32com.client import Dispatch
# Start excel application
xl = Dispatch('Excel.Application')
# Open existing excel file
book = xl.Workbooks.Open('workbook.xlsx')
# Some arbitrary excel operations ...
# Close excel application without saving file
book.Close(SaveChanges=False)
xl.Quit()

'[Errno 13]' Permission denied: Openpyxl and win32com conflict

I'm using win32com to run macros in excel and openpyxl to modify cell values. In the process of debugging, I attempted to create a simplified version of existing code but still ran into the same
[Errno 13] Permission denied:'C:\\Users\\NAME\\Desktop\\old\\Book1.xlsx'.
I believe that the error is caused by the two packages (win32com and openpyxl) opening the same file and, when attempting to save/close, cannot close the instance open in the other package.
When I attempt to save/close with openpyxl before saving/closing with win32com, I run into the permission denied error. This makes sense; Openpyxl probably does not have permission to close the excel instance open through win32com. Code is below:
wb.save(r"C:\Users\NAME\Desktop\old\Book1.xlsx")
xel.Workbooks(1).Close(SaveChanges=True)
However, when I switch the order:
xel.Workbooks(1).Close(SaveChanges=True)
wb.save(r"C:\Users\NAME\Desktop\old\Book1.xlsx")
Excel attempts to save a backup file (randomly named "522FED10" or "35C0ED10", etc.) and when I press save, Excel crashes.
What's the workaround? I was thinking that you could use win32com to run the macros, save under a different filename, then use openpyxl to access that file and edit values. However, this is extremely inefficient (I'm dealing with excel files that have hundreds of thousands of rows of data). I could consider just using win32com, but that would require a revamp of a system.
Simple code:
import openpyxl as xl
import win32com.client
xel=win32com.client.Dispatch("Excel.Application")
xel.Workbooks.Open(Filename=r"C:\Users\NAME\Desktop\old\Book1.xlsx")
wb = xl.load_workbook(r"C:\Users\NAME\Desktop\old\Book1.xlsx")
ws = wb.active
xel.visible = False
xel.Cells(1,1).Value = 'Hello Excel'
ws.cell(row = 1,column = 2).value = "test"
xel.Workbooks(1).Close(SaveChanges=True)
wb.save(r"C:\Users\NAME\Desktop\old\Book1.xlsx")
Current issue
You should definitely not mix win32com and openpyxl operations.
The win32com statement xel.Workbooks.Open() loads the workbook contents into a memory space controlled by an Excel process. The openpyxl xl.load_workbook() statement on the other hand loads the workbook contents into a completely separate memory space controlled by a Python process.
Hence any subsequent win32com commands will do nothing to affect the workbook that's living inside the python-process-controlled memory, and vice versa any openpxyl commands will do nothing to affect the workbook that's living inside the Excel-process-controlled memory.
Solution
You mentioned that you have to run some excel macros. This rules out an openpyxl-only solution. My suggestion would be to use xlwings, which is in essence a powerful and user-friendly wrapper around the win32com API.
Here is a simple example of how you can execute Excel macros and manually update cell values within a single python script:
import xlwings as xw
# Start Excel app (invisibly in the background)
app = xw.App(visible=False)
# Load excel file into active Excel app
book = app.books.open(r"Book1.xlsm")
# Instruct Excel to execute the pre-existing excel macro named "CleanUpMacro"
book.macro("CleanUpMacro")()
# Instruct Excel to write a cell value in the first sheet
book.sheets["Sheet1"].range('A1').value = 42
# Save workbook and terminate Excel application
book.save()
book.close()
app.kill()

EXCEL application window not closing on workbook.close()

When I open a workbook using
wbTest = xlwings.Book('test.xlsm')
the EXCEL application opens and shows the workbook. But when doing a
wbTest.close()
afterwards, the workbook closes, but the EXCEL window stays open so that I have to close it manually, even though xlwings.apps returns an empty list:
Is there a way to close the EXCEL window as soon as the last workbook closes?
In the official documentation (readthedocs) I could not find anything solving this question, so far.
On Windows, xlwings currently requires a workbook in order to communicate with Excel. But you can achieve want you want by quitting the app rather than just closing the workbook (you could check first if there are more than one workbooks open in that app via len(wbTest.app.books)):
wbTest.app.quit()
You may want to save the workbook first or alternatively there's also app.kill().
Sometimes, a loaded workbook contains macros which leave the application in an "unsaved" state, even when no changes had been made, yet. Using wbTest.app.quit(), in this case, will prompt a save dialog, which I don't want to see. Using wbTest.app.kill() would close the workbook (and close the EXCEL window), but on re-opening EXCEL, a recovery dialog for the killed wbTest workbook will be displayed, which I'd like to avoid.
So, here the overall solution which works for me:
import xlwings
import tempfile
import os
# ... some code creating at least one workbook "wbTest"
# check, if there is only one workbook left and we don't want to save it
if len(xlwings.apps) == 1:
#save the remaining workbook into temporary folder
wbTest.save(
os.path.join(
tempfile.gettempdir(),
'test.xlsm',
)
)
# close the application
wbTest.app.quit()
Thanks for all the hints.
Along with the proposed solution given by the Author, I figured out that sometimes when you have macros on the Personal Macro Workbook, the counter of opened workbooks changes. That's why I added a simple function that handles that situation.
In my case sometimes I work with multiple excel files opened and this is very handy to get rid of the workbooks that are affected by the macros but you don't want to be closed.
def quit_excel(wb):
"""wb: workbook object from xlwings"""
print(wb.app.books) # for debugging and visualization of opened workbooks
# look if PERSONAL.XLSB is in the list of books associated with the Excel App
if "PERSONAL.XLSB" in [b.name for b in wb.app.books]:
if len(wb.app.books) == 2:
print("personal, 2, quitting")
wb.app.quit()
else:
print("personal, closing")
wb.close()
else:
if len(wb.app.books) == 1:
print("no personal, 1, quitting")
wb.app.quit()
else:
print("no personal, closing")
wb.close()
I wanted share a solution that may help some users with a slight variation to the original problem. In some scenarios I had multiple excel workbooks open and before running the code therefore I only wanted to close the workbook that the script opened and not the entire excel application. Here's my solution that will work for this scenario.
wb = xw.Book(file_path)
excel_app = xw.apps.active
#
# do stuff with workbook
#
# close workbook if more then one workbook is open.
# you won't get empty grey excel app since you have another workbook open.
if xw.apps.count > 1:
wb.close()
# close excel application if only one workbook is open
else:
excel_app.quit()

Access excel with macros using openpyxl

I have an .xlsm file with lots of macros and sheets, which provides some graphs when filled in. I want to open the .xlsm file in python and fill some values to the macros in order to get the graphs . I have tried the following code but it seems that when I open the new file a message that the file is corrupted pops-up.
I use python 2.74 and openpyxl version is 2.4.8
import openpyxl
from xlwt import easyxf
book = openpyxl.load_workbook('macroexcel.xlsm',keep_vba=True) #opens excel file
sheet = book.get_sheet_by_name('SheetName') #Get the sheet name
sheet['K34'] = 'Value' #Assign value to a cell connected to the macro
book.save('newexcel.xlsm') #Save
Is there a way to get access to the values in the macros, select them and extract the graphs using python.?
Thanks.
Try this - How To: Add and Call Excel Macro from Python Using Pandas, Win32 and PyMySQL.
It suggests Python to initiate a win32com.client.Dispatch('Excel.Application') to start Excel. Then, having access to the application layer, xl.Application.Run("Macro1").

Categories

Resources