是否有任何有效的方法使用任何Python模块,如PyWind32
与现有的Native OS对话框,如“另存为”框交互?
我试图search谷歌,但没有帮助。
编辑:
1:当用户在Web应用程序上单击“另存为”对话框时,“另存为”对话框被触发。
2:任何build议,欢迎处理任何本地操作系统对话框已经触发使用Python。(不需要特定于Selenium webdriver,我正在寻找一个通用的build议。)
(当我发布这个问题时,我认为通过“与对话框交互”将暗示它是现有的,就好像我能够创build一个对话框一样,那么当然可以和我的程序控制下的交互。在阅读了前两个答案之后,我意识到自己并没有明确的说法,这就是为什么编辑)
谢谢
当寻找一个可能的解决方案时,我遇到了SO和其他几个解决方案。 其中一些使用AutoIT
,或编辑浏览器配置文件,使其直接存储文件没有提示。
我发现所有这个解决方案太具体,就像你可以通过编辑浏览器配置文件来解决另存为对话框的问题,但如果以后你需要处理一些其他窗口,那么你卡住了。 对于使用AutoIT
是矫枉过正,这直接冲突的事实,我选择Python
来做这个任务。 (我的意思是Python
本身是如此强大,取决于其他一些工具是严格的没有任何Pythonist否)
因此,经过漫长的搜索寻找一个可能的通用解决方案,这个问题不仅为任何正在寻找处理任何本机操作系统对话框,如“另存为”,“文件上传”等在使用硒自动化Web应用程序网络驱动程序,也适用于任何想使用Python
API与特定窗口进行交互的人。
此解决方案使用Python
的Win32gui
, SendKeys
模块。 我将首先解释一个通用的方法,以获得所需的任何窗口,然后添加一个小代码,这也将使这个可用,同时使用seleniumium Webdriver自动化Web应用程序。
通用解决方案 ::
import win32gui import re import SendKeys class WindowFinder: """Class to find and make focus on a particular Native OS dialog/Window """ def __init__ (self): self._handle = None def find_window(self, class_name, window_name = None): """Pass a window class name & window name directly if known to get the window """ self._handle = win32gui.FindWindow(class_name, window_name) def _window_enum_callback(self, hwnd, wildcard): '''Call back func which checks each open window and matches the name of window using reg ex''' if re.match(wildcard, str(win32gui.GetWindowText(hwnd))) != None: self._handle = hwnd def find_window_wildcard(self, wildcard): """ This function takes a string as input and calls EnumWindows to enumerate through all open windows """ self._handle = None win32gui.EnumWindows(self._window_enum_callback, wildcard) def set_foreground(self): """Get the focus on the desired open window""" win32gui.SetForegroundWindow(self._handle) win = WindowFinder() win.find_window_wildcard(".*Save As.*") win.set_foreground() path = "D:\\File.txt" #Path of the file you want to Save ent = "{ENTER}" #Enter key stroke. SendKeys.SendKeys(path) #Use SendKeys to send path string to Save As dialog SendKeys.SendKeys(ent) #Use SendKeys to send ENTER key stroke to Save As dialog
要使用此代码,您需要提供一个字符串,它是您想要获得的窗口的名称,在这种情况下是“另存为”。 所以同样,你可以提供任何名称,并获得该窗口的重点。 一旦你有所需的窗口的焦点,那么你可以使用SendKeys
模块发送按键到窗口,在这种情况下,包括发送文件路径,你要保存文件和ENTER
。
具体到seleniumium Webdriver ::
上面指定的代码段可以用来处理本地操作系统对话框,这些对话框在使用seleniumium Webdriver
的自动化过程中通过Web应用程序触发,只需添加一点点代码。
我在使用这个代码时遇到的问题是,一旦您的自动化代码点击任何触发本地操作系统对话框窗口的Web Element
,控件就会停留在此处,等待本地操作系统对话框窗口的任何操作。 所以基本上你被困在这一点上。
解决方法是使用Python
threading
模块生成一个新thread
并使用它来单击Web Element
以触发本地操作系统对话框,并且您的父线程将正常移动以使用上面显示的代码查找窗口。
#Assume that at this point you are on the page where you need to click on a Web Element to trigger native OS window/dialog box def _action_on_trigger_element(_element): _element.click() trigger_element = driver.find_element_by_id('ID of the Web Element which triggers the window') th = threading.Thread(target = _action_on_trigger_element, args = [trigger_element]) #Thread is created here to call private func to click on Save button th.start() #Thread starts execution here time.sleep(1) #Simple Thread Synchronization handle this case. #Call WindowFinder Class win = WindowFinder() win.find_window_wildcard(".*Save As.*") win.set_foreground() path = "D:\\File.txt" #Path of the file you want to Save ent = "{ENTER}" #Enter key stroke. SendKeys.SendKeys(path) #Use SendKeys to send path string to Save As dialog SendKeys.SendKeys(ent) #Use SendKeys to send ENTER key stroke to Save As dialog #At this point the native OS window is interacted with and closed after passing a key stroke ENTER. # Go forward with what ever your Automation code is doing after this point
注意::
在自动化Web应用程序中使用上述代码时,请检查要查找的窗口的名称,并将其传递给find_window_wildcard()
。 窗口的名字是依赖于浏览器的。 例如,单击元素上传文件时触发的窗口在Firefox
称为“文件上载”,在Chrome
称为“打开”。 使用Python2.7
我希望这将有助于任何正在寻找类似解决方案的人,不管是以任何通用形式使用它,还是使Web应用程序自动化。
编辑:
如果你试图通过命令行参数运行你的代码,然后尝试使用Win32gui
来查找窗口,并使用原始程序线程单击该元素(在此处单击此处使用该线程)来查找该窗口。 原因是urllib库将在使用线程创建新连接时引发错误。)
参考文献::
SO问题
SenKeys
Win32gui
有一个名为win32ui的Python模块。 它在Python for Windows扩展包中找到。 你需要CreateFileDialog函数。
文档
编辑:这是一个保存对话框的例子。 检查其他设置的文档。
import win32ui if __name__ == "__main__": select_dlg = win32ui.CreateFileDialog(0, ".txt", "default_name", 0, "TXT Files (*.txt)|*.txt|All Files (*.*)|*.*|") select_dlg.DoModal() selected_file = select_dlg.GetPathName() print selected_file