6

Python モジュールを使用して、PyWind32「名前を付けて保存」ボックスなどの既存のネイティブ OS ダイアログ ボックスとやり取りする効率的な方法はありますか?

Googleで検索してみましたが、助けにはなりませんでした。

編集:

1: ユーザーが Web アプリケーションの [名前を付けて保存] ダイアログ ボックスをクリックすると、[名前を付けて保存] ダイアログ ボックスがトリガーされます。

2: Python を使用して既にトリガーされているネイティブ OS ダイアログ ボックスを処理するための提案は大歓迎です (Selenium webdriver に固有である必要はありません。一般的な提案を探しています)。

(質問を投稿したとき、「ダイアログボックスと対話する」ことは、それが既存のものであることを暗黙のうちに意味するのではないかと考えました.最初の 2 つの回答を読んだ後、私は明確に明確ではないことに気付きました。

ありがとう

4

2 に答える 2

8

これに対する可能な解決策を探しているときに、SOなどでいくつかの解決策に出くわしました。それらの一部はAutoIT、プロンプトなしでファイルを直接保存するために、ブラウザープロファイルを使用または編集していました。

ブラウザのプロファイルを編集することで [名前を付けて保存] ダイアログの問題を克服できるように、このソリューションはすべて具体的すぎることがわかりましたが、後で他のウィンドウを処理する必要がある場合は行き詰まります。使用するAutoITのはやり過ぎです。これは、私Pythonがこのタスクを実行することを選択したという事実に直接衝突します。(Pythonつまり、それ自体が非常に強力です。他のツールに応じて、Pythonistにとって厳密にNO NOです)

したがって、この問題に対する可能な一般的な解決策を長い間探した後、Selenium を使用して Web アプリケーションを自動化するプロセスで、「名前を付けて保存」、「ファイルのアップロード」などのネイティブ OS ダイアログボックスを処理しようとしている人だけでなく、 Web ドライバーだけでなく、 PythonAPIのみを使用して特定のウィンドウとやり取りしたい人にも。

このソリューションは、のモジュールを利用Win32guiSendKeysます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 アプリケーションを介してトリガーされるネイティブ OS ダイアログ ボックスを処理することができます。これSelenium Webdriverには、コードを少し追加します。

このコードを使用しているときに直面する問題は、自動化コードがWeb Elementネイティブ OS ダイアログ ウィンドウをトリガーするものをクリックすると、ネイティブ OS ダイアログ ウィンドウでのアクションを待っている時点でコントロールがスタックすることです。したがって、基本的にはこの時点で立ち往生しています。

回避策は、新しいthreadusingPython threadingモジュールを生成し、それをクリックしてWeb Elementネイティブ OS ダイアログ ボックスをトリガーすることです。親スレッドは、上記のコードを使用してウィンドウを見つけるために通常どおりに移動します。

#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 ライブラリがエラーをスローするためです。)

参考文献::

そう質問

センキー

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 に答える