В поисках возможного решения для этого я наткнулся на несколько решений для SO и других. Некоторые из них использовали AutoIT
или редактировали профиль браузера, чтобы он сохранял файл напрямую без запроса.
Я нашел все это решение слишком специфичным, так как вы можете решить проблему с диалоговым окном «Сохранить как», отредактировав профиль браузера, но если позже вам нужно будет обработать какое-то другое окно, вы застряли. Поскольку использование AutoIT
является излишним, это напрямую противоречит тому факту, что я выбираю Python
для выполнения этой задачи. (Я имею в виду, что Python
сам по себе такой мощный, в зависимости от какого-то другого инструмента строго НЕТ НЕТ для любого Pythonist)
Итак, после долгого поиска возможного общего решения этой проблемы, которое не только служит любому, кто хочет обрабатывать любые диалоговые окна собственной ОС, такие как «Сохранить как», «Загрузка файла» и т. д., в процессе автоматизации веб-приложения с использованием селена веб-драйвер, но и любому, кто хочет взаимодействовать с конкретным окном, используя только Python
API.
В этом решении используются Win32gui
, SendKeys
модули Python
. Сначала я объясню общий метод для получения доступа к любому желаемому окну, а затем небольшое добавление кода, которое также сделает его пригодным для использования при автоматизации веб-приложения с помощью Selenium Webdriver.
Общее решение::
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::
Указанный выше сегмент кода можно использовать для обработки собственных диалоговых окон ОС, которые запускаются через веб-приложение во время автоматизации с использованием 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
ПРИМЕЧАНИЕ::
При использовании приведенного выше кода для автоматизации веб-приложения проверьте имя окна, которое вы хотите найти, и передайте его find_window_wildcard()
. Название окон зависит от браузера. Например. Окно, которое запускается, когда вы нажимаете на элемент для загрузки файла, называется «Загрузка файла» в Firefox
и «Открыть» в Chrome
. Использует Python2.7
Я надеюсь, что это поможет любому, кто ищет подобное решение, использовать ли его в какой-либо универсальной форме или для автоматизации веб-приложения.
ИЗМЕНИТЬ:
Если вы пытаетесь запустить свой код с помощью аргументов командной строки, попробуйте использовать поток, чтобы найти окно, используя Win32gui
, и используйте исходный программный поток, чтобы щелкнуть элемент (который щелкается здесь с помощью потока). Причина в том, что библиотека urllib выдаст ошибку при создании нового соединения с использованием потока.)
Использованная литература::
SO Вопрос
SenKeys
Win32gui
person
abhi
schedule
27.06.2013
ctypes
для прямого доступа к Win32 API. Я также ограничил бы поиск правильного дескриптора окна только теми, которые принадлежат процессу браузера, на случай, если у вас открыто какое-либо другое приложение с активным диалоговым окном «Сохранить как». Тем не менее, я бы, вероятно, никогда не использовал что-то подобное на практике. Если бы я хотел протестировать такие вещи, как загрузка/выгрузка, я бы сделал это с чем-то вродеmechanize
, предполагая, что он поддерживает такие вещи, в противном случае свернул бы свой собственный сhttplib
или чем-то подобным. - person Aya   schedule 27.06.2013