如何用Selenium WebDriver按名称关闭指定文档?及特定Office文件关闭方法问询
Hey there! Let's break down how to solve your problem—since WindowsUtils.killByName("excel.exe") wipes out every open Excel file, we need a more targeted approach.
First, a quick heads-up: Selenium WebDriver is built for browser automation, so it can't directly interact with desktop apps like Excel or Word. To handle Office documents, we'll use either Office COM Automation (the most reliable method) or target specific processes (only works if you configure Office to open each document in its own process).
Option 1: Use Office COM Automation (Recommended)
This method directly talks to the Office application to close only the document you want. It preserves other open files and handles standard Office behaviors like save prompts properly.
Example for Excel (Java with Jacob Library)
Jacob lets you access Windows COM objects from Java. First, add the Jacob library to your project (you'll need the JAR and matching 32/64-bit DLL):
import com.jacob.activeX.ActiveXComponent; import com.jacob.com.Dispatch; import com.jacob.com.Variant; public class SpecificOfficeDocClosure { public static void closeTargetExcel(String targetDocName) { ActiveXComponent excelApp = new ActiveXComponent("Excel.Application"); try { // Set to true if you need to see the Excel window; false works too excelApp.setProperty("Visible", new Variant(true)); Dispatch workbooks = excelApp.getProperty("Workbooks").toDispatch(); int workbookCount = Dispatch.call(workbooks, "Count").getInt(); // Loop backwards to avoid skipping items when closing for (int i = workbookCount; i >= 1; i--) { Dispatch workbook = Dispatch.call(workbooks, "Item", new Variant(i)).toDispatch(); String currentDocName = Dispatch.call(workbook, "Name").getString(); if (currentDocName.equals(targetDocName)) { // Close without saving (pass true to save changes) Dispatch.call(workbook, "Close", new Variant(false)); break; } } } finally { // Don't quit the entire Excel app—just release the COM object excelApp.safeRelease(); } } public static void main(String[] args) { closeTargetExcel("Q4_Sales.xlsx"); } }
Example for Word (Python with pywin32)
If you prefer Python, the pywin32 library makes COM interactions straightforward:
import win32com.client def close_target_word(target_doc_name): try: word_app = win32com.client.GetActiveObject("Word.Application") for doc in word_app.Documents: if doc.Name == target_doc_name: # Close without saving (change to True to save) doc.Close(SaveChanges=False) break except Exception as e: print(f"Error closing document: {e}") # Call the function close_target_word("Project_Proposal.docx")
Option 2: Target Specific Processes (Only for Single-Document Office Processes)
By default, Office opens all documents in one process. If you change this setting (File > Options > Advanced > "Don't allow multiple instances of Excel"), each document gets its own process. Then you can find the process linked to your target document and terminate it.
Java Example with JNA
This uses JNA to query process command lines (which include the document path):
import com.sun.jna.platform.win32.Kernel32; import com.sun.jna.platform.win32.Psapi; import com.sun.jna.platform.win32.WinDef; import com.sun.jna.platform.win32.WinNT; import com.sun.jna.ptr.IntByReference; import java.util.ArrayList; import java.util.List; public class OfficeProcessKiller { public static List<WinNT.HANDLE> findOfficeProcessesByDoc(String processName, String docName) { List<WinNT.HANDLE> targetProcesses = new ArrayList<>(); WinDef.DWORDByReference processIds = new WinDef.DWORDByReference(); int bytesReturned = 0; // Get all running process IDs if (!Psapi.INSTANCE.EnumProcesses(processIds.getPointer(), new WinDef.DWORD(1024), new WinDef.DWORDByReference(new WinDef.DWORD(bytesReturned)))) { return targetProcesses; } int numProcesses = bytesReturned / Kernel32.INSTANCE.GetNativeLongSize(); int[] pids = processIds.getPointer().getIntArray(0, numProcesses); for (int pid : pids) { WinNT.HANDLE processHandle = Kernel32.INSTANCE.OpenProcess( WinNT.PROCESS_QUERY_INFORMATION | WinNT.PROCESS_VM_READ, false, pid ); if (processHandle != null) { char[] pathBuffer = new char[1024]; if (Psapi.INSTANCE.GetProcessImageFileName(processHandle, pathBuffer, new WinDef.DWORD(pathBuffer.length)) > 0) { String exePath = new String(pathBuffer).trim(); if (exePath.endsWith(processName)) { // Check if the command line includes the target document char[] cmdBuffer = new char[4096]; if (Psapi.INSTANCE.GetCommandLine(processHandle, cmdBuffer, new WinDef.DWORD(cmdBuffer.length)) > 0) { String cmdLine = new String(cmdBuffer).trim(); if (cmdLine.contains(docName)) { targetProcesses.add(processHandle); } else { Kernel32.INSTANCE.CloseHandle(processHandle); } } } else { Kernel32.INSTANCE.CloseHandle(processHandle); } } } } return targetProcesses; } public static void terminateProcesses(List<WinNT.HANDLE> processes) { for (WinNT.HANDLE handle : processes) { Kernel32.INSTANCE.TerminateProcess(handle, 0); Kernel32.INSTANCE.CloseHandle(handle); } } public static void main(String[] args) { List<WinNT.HANDLE> excelProcesses = findOfficeProcessesByDoc("excel.exe", "Q4_Sales.xlsx"); terminateProcesses(excelProcesses); } }
Key Takeaways
- COM Automation is best: It's the official way to interact with Office, avoids closing unrelated files, and respects Office's built-in logic.
- Process killing is a fallback: Only use this if you've configured Office to run each document in a separate process, and be aware it will force-close the document (no save prompts).
内容的提问来源于stack exchange,提问作者Jagadeesh

