¿Cuál es la mejor manera de interactuar con los cuadros de diálogo de SO nativos ya abiertos como(Guardar AS) usando Python?
windows winapi (2)
¿Hay alguna manera eficiente de usar cualquier módulo de Python como PyWind32
para interactuar con cuadros de diálogo de SO nativos ya existentes como los cuadros de ''Guardar como''?
Intenté buscar en Google pero no recibí ayuda.
EDITAR:
1: El cuadro de diálogo Guardar como se activa cuando el usuario hace clic en un cuadro de diálogo Guardar como en una aplicación web.
2: Cualquier sugerencia es bienvenida para manejar cualquier cuadro de diálogo de SO nativo que ya se haya activado usando Python. (No es necesario ser específico de Selenium webdriver, estoy buscando una sugerencia genérica).
(Cuando estaba publicando la pregunta, pensé que "interactuar con un cuadro de diálogo" significará implícitamente que es una existente, como si fuera capaz de crear una, entonces seguramente puedo interactuar con ella, ya que está bajo el control de mis programas. Después de leer las primeras 2 respuestas, me di cuenta de que no estaba explícitamente claro. Por eso el EDIT)
Gracias
Hay un módulo de Python llamado win32ui. Se encuentra en el paquete de extensiones de Python para Windows . Desea la función CreateFileDialog.
Editar: Este es un ejemplo de diálogo de guardar. Verifique la documentación para las otras configuraciones.
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
Mientras buscaba una posible solución para esto, encontré varias soluciones sobre SO y otras. Algunos de ellos usaban AutoIT
, o el perfil de los navegadores de edición para hacer que almacenara el archivo directamente sin un aviso.
Encontré toda esta solución demasiado específica como si pudiera solucionar el problema del diálogo Guardar como editando el perfil del navegador, pero si más adelante necesita manejar alguna otra ventana, entonces se queda atascado. Para usar AutoIT
es excesivo, esto colisiona directamente por el hecho de elegir Python
para hacer esta tarea. (Me refiero a Python
es en sí mismo tan poderoso, dependiendo de alguna otra herramienta es estricto NO NO para cualquier Pythonist)
Así que después de una larga búsqueda de una posible solución genérica para este problema que no solo sirve a cualquiera que esté tratando de manejar cualquier cuadro de diálogo de SO nativo como ''Guardar como'', ''Subir archivo'', etc. en el proceso de automatizar una aplicación web usando selenio controlador web, sino también a cualquiera que quiera interactuar con una ventana específica utilizando solo API de Python
.
Esta solución hace uso de los módulos Win32gui
, SendKeys
de Python
. Explicaré primero un método genérico para obtener cualquier ventana deseada y luego una pequeña adición de código que también lo hará utilizable al automatizar una aplicación web usando Selenium Webdriver.
Solución Genérica ::
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
Para usar este código, debe proporcionar una cadena que es el nombre de la ventana que desea obtener, que en este caso es ''Guardar como''. De manera similar, puede proporcionar cualquier nombre y enfocar esa ventana. Una vez que tiene el foco de la ventana deseada, puede usar el módulo SendKeys
para enviar los trazos de tecla a la ventana, que en este caso incluye el envío de la ruta del archivo donde desea guardar el archivo y ENTER
.
Específico para Selenium Webdriver ::
El segmento de código especificado anteriormente se puede usar para manejar cuadros de diálogo de SO nativos que se activan a través de una aplicación web durante la automatización usando Selenium Webdriver
con la adición de un poco de código.
El problema al que me enfrenté al usar este código es que una vez que su código de automatización hace clic en cualquier Web Element
que activa una ventana de diálogo del sistema operativo nativo, el control se atascará en ese punto esperando cualquier acción en la ventana de diálogo del sistema operativo nativo. Entonces, básicamente estás estancado en este punto.
El trabajo consiste en generar un nuevo thread
utilizando el módulo de threading
Python
y usarlo para hacer clic en el Web Element
para activar el cuadro de diálogo del sistema operativo nativo y el hilo padre se moverá normalmente para encontrar la ventana utilizando el código que mostré arriba.
#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
NOTA::
Cuando utilice el código anterior para automatizar una aplicación web, verifique el nombre de la ventana que desea buscar y páselo a find_window_wildcard()
. El nombre de las ventanas depende del navegador. Por ejemplo, una ventana que se activa al hacer clic en un Elemento para cargar un archivo se denomina ''Carga de archivos'' en Firefox
y Abrir en Chrome
. Utiliza Python2.7
Espero que esto ayude a cualquiera que esté buscando una solución similar, ya sea para usarla en cualquier forma genérica o para automatizar una aplicación web.
EDITAR:
Si está intentando ejecutar su código a través de argumentos de línea de comando, intente usar la Win32gui
para encontrar la ventana usando Win32gui
y use el hilo del programa original para hacer clic en el elemento (que se hace clic aquí usando el hilo). El motivo es que la biblioteca urllib arrojará un error al crear una nueva conexión utilizando el hilo.
Referencias ::