abh*_*bhi 5 python windows winapi selenium pywin32
是否有任何有效的方法使用任何Python模块,如PyWind32与现有的本机操作系统对话框,如"另存为"框交互?
我尝试在Google上搜索但没有任何帮助.
编辑:
1:当用户单击Web应用程序上的"另存为"对话框时,将触发"另存为"对话框.
2:欢迎任何建议处理已经使用Python触发的任何本机操作系统对话框.(不需要特定于Selenium webdriver,我正在寻找一个通用的建议.)
(当我发布问题时,我认为通过'与对话框交互'将隐含地意味着它是一个现有的,好像我能够创建一个然后肯定我可以与它进行交互,因为它在我的程序控制下.在阅读了前两个答案之后,我意识到我并没有明确说明.这就是为什么EDIT)
谢谢
在寻找可能的解决方案时,我遇到了SO和其他方面的几个解决方案.他们中的一些人正在使用AutoIT或编辑浏览器配置文件,以使其直接存储文件而无需提示.
我发现所有这个解决方案都太具体了,就像你可以通过编辑浏览器配置文件来解决"另存为"对话框的问题,但是如果以后你需要处理其他窗口那么你就会陷入困境.对于使用AutoIT是过度杀伤,这直接碰撞我选择Python执行此任务的事实.(我的意思Python是它本身如此强大,取决于其他一些工具严格禁止任何Python教徒)
所以经过长时间搜索这个问题的可能的通用解决方案,它不仅为任何想要在使用selenium自动化Web应用程序的过程中处理任何Native OS对话框(如"另存为","文件上载"等)提供服务. 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
Run Code Online (Sandbox Code Playgroud)
要使用此代码,您需要提供一个字符串,该字符串是您要获取的窗口的名称,在本例中为"另存为".所以类似地,您可以提供任何名称并使该窗口集中.获得所需窗口的焦点后,您可以使用SendKeys模块向窗口发送击键,在这种情况下,包括发送要保存文件的文件路径ENTER.
特定于Selenium Webdriver ::
上面指定的代码段可用于处理本机OS对话框,这些对话框在自动化期间通过Web应用程序使用Selenium Webdriver,只需添加一点代码即可.
您在使用此代码时遇到的问题是,一旦您的自动化代码点击任何Web Element触发本机操作系统对话框窗口的任何内容,控件将停留在该点,等待本机操作系统对话框窗口上的任何操作.所以基本上你会陷入困境.
解决方法是生成一个新的thread使用Python 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
Run Code Online (Sandbox Code Playgroud)
注意::
在自动化Web应用程序中使用上述代码时,请检查要查找的窗口的名称并将其传递给find_window_wildcard().Windows的名称取决于浏览器.例如,单击要上载文件的元素时触发的窗口称为"文件上载" Firefox和"打开" Chrome.用途Python2.7
我希望这可以帮助任何正在寻找类似解决方案的人,无论是以任何通用形式使用它还是自动化Web应用程序.
编辑:
如果您尝试通过命令行参数运行代码,则尝试使用该线程查找使用的窗口,Win32gui并使用原始程序线程单击该元素(使用该线程单击此处).原因是urllib库在使用线程创建新连接时会抛出错误.)
参考文献::