6

是否有任何有效的方法使用任何 Python 模块,例如PyWind32与现有的本机操作系统对话框(如“另存为”框)进行交互?

我尝试在 Google 上搜索,但没有任何帮助。

编辑:

1:当用户单击 Web 应用程序上的“另存为”对话框时,会触发“另存为”对话框。

2:欢迎任何建议来处理已经使用 Python 触发的任何本机操作系统对话框。(不需要特定于 Selenium webdriver,我正在寻找一个通用的建议。)

(当我发布这个问题时,我认为“与对话框交互”将暗示它是一个现有的对话框,就好像我能够创建一个对话框一样,然后我肯定可以与它交互,因为它在我的程序控制之下。阅读前 2 个答案后,我意识到我并不清楚。这就是为什么编辑)

谢谢

4

2 回答 2

8

在为此寻找可能的解决方案时,我遇到了关于 SO 和其他方面的几种解决方案。他们中的一些人正在使用AutoIT或编辑浏览器配置文件以使其直接存储文件而无需提示。

我发现所有这些解决方案都太具体了,就像您可以通过编辑浏览器配置文件来克服“另存为”对话框的问题,但如果稍后您需要处理其他一些窗口,那么您就会被卡住。因为使用AutoIT是矫枉过正,这直接与我选择Python执行此任务的事实相冲突。(我的意思Python是它本身是如此强大,取决于其他一些工具对任何 Pythonist 来说都是严格的 NO NO)

因此,经过长时间搜索该问题的可能通用解决方案后,该解决方案不仅适用于希望在使用 selenium 自动化 Web 应用程序的过程中处理任何本机操作系统对话框(如“另存为”、“文件上传”等)的人Web 驱动程序,但也适用于任何想要仅使用PythonAPI 与特定窗口交互的人。

该解决Win32gui方案使用SendKeys. Python我将首先解释一个通用方法来获取所需的任何窗口,然后添加一个小代码,这也将使其在使用 Selenium 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.

特定于 Selenium Webdriver::

上面指定的代码段可用于处理在自动化使用过程中通过 Web 应用程序触发的本机操作系统对话框Selenium Webdriver,只需添加一点代码。

我在使用此代码时将面临的问题是,一旦您的自动化代码单击任何Web Element触发本机 OS 对话窗口的内容,控件将停留在该点等待本机 OS 对话窗口上的任何操作。所以基本上你被困在这一点上。

解决方法是生成一个新的threadusingPython threading模块并使用它单击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 库在使用线程创建新连接时会抛出错误。)

参考::

所以问题

SenKeys

Win32gui

于 2013-06-27T18:16:57.393 回答
2

有一个名为 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
于 2013-06-21T12:57:07.980 回答