使用Python获取Active窗口

Vin*_*d K 19 python active-window

我想使用python在屏幕上获取活动窗口.

例如,路由器的管理界面,您输入用户名和密码作为admin

我希望使用python捕获该管理界面以自动输入用户名和密码.

为了做到这一点,我需要进口什么?

Wil*_*ers 20

在Windows上,您可以使用python for windows扩展(http://sourceforge.net/projects/pywin32/):

from win32gui import GetWindowText, GetForegroundWindow
print GetWindowText(GetForegroundWindow())
Run Code Online (Sandbox Code Playgroud)

下面的代码是针对python 3的:

from win32gui import GetWindowText, GetForegroundWindow
print(GetWindowText(GetForegroundWindow()))
Run Code Online (Sandbox Code Playgroud)

(在http://scott.sherrillmix.com/blog/programmer/active-window-logger/上找到)


Mit*_*ers 18

感谢 Nuno André 的回答,他展示了如何使用 ctypes 与 Windows API 交互。我已经使用他的提示编写了一个示例实现。

ctypes库自 v2.5 起包含在 Python 中,这意味着几乎每个用户都拥有它。而且它是一种比旧的和死的库更干净的界面win32gui(在撰写本文时于 2017 年最后一次更新)。((2020 年末更新:死win32gui库已重新命名为pywin32,因此如果您想要一个维护的库,它现在又是一个有效的选择。但该库比我的代码慢 6%。))

文档在这里:https : //docs.python.org/3/library/ctypes.html(如果你想编写自己的代码,你必须阅读它的使用帮助,否则你会导致分段错误崩溃,呵呵。)

基本上,ctypes 包括最常见的 Windows DLL 的绑定。这是在纯 Python 中检索前景窗口标题的方法,无需外部库!只是内置的ctypes!:-)

ctypes 最酷的地方是你可以谷歌任何你需要的任何Windows API,如果你想使用它,你可以通过 ctypes 来做!

Python 3 代码:

from typing import Optional
from ctypes import wintypes, windll, create_unicode_buffer

def getForegroundWindowTitle() -> Optional[str]:
    hWnd = windll.user32.GetForegroundWindow()
    length = windll.user32.GetWindowTextLengthW(hWnd)
    buf = create_unicode_buffer(length + 1)
    windll.user32.GetWindowTextW(hWnd, buf, length + 1)
    
    # 1-liner alternative: return buf.value if buf.value else None
    if buf.value:
        return buf.value
    else:
        return None
Run Code Online (Sandbox Code Playgroud)

性能非常好:0.01我电脑上的 MILLISECONDS(0.00001秒)。

也可以在 Python 2 上进行非常小的更改。如果您使用的是 Python 2,我认为您只需删除类型注释(from typing import Optional -> Optional[str])。:-)

享受!

Win32技术说明:

length变量是UTF-16(Windows Wide“Unicode”)字符中实际文本的长度(它不是字节数。)我们必须添加+ 1以在 C 样式字符串的末尾为空终止符添加空间。如果我们不这样做,缓冲区中将没有足够的空间来容纳实际文本的最终真实字符,Windows 将截断返回的字符串(这样做是为了确保它适合超级重要的最终字符串 Null -终结者)。

create_unicode_buffer函数为那么多 UTF-16 字符分配空间。

大多数(或全部?总是阅读 Microsoft 的 MSDN 文档!)与 Unicode 文本相关的 Windows API 将缓冲区长度作为字符,而不是字节。

还要仔细查看函数调用。有些以W(例如GetWindowTextLengthW)结尾。这代表“宽字符串”,它是 Unicode 字符串的 Windows 名称。执行这些W调用以获得正确的 Unicode 字符串(具有国际字符支持)非常重要。

PS:Windows 使用 Unicode 已经很长时间了。我知道 Windows 10 是完全Unicode 并且只需要W函数调用的事实。我不知道旧版本的 Windows 使用其他多字节字符串格式的确切截止日期,但我认为它是在 Windows Vista 之前,谁在乎呢?旧的 Windows 版本(甚至 7 和 8.1)已经过时并且不受 Microsoft 支持。

再次......享受!:-)

2020 年末更新,基准测试与pywin32库:

import time

import win32ui

from typing import Optional
from ctypes import wintypes, windll, create_unicode_buffer

def getForegroundWindowTitle() -> Optional[str]:
    hWnd = windll.user32.GetForegroundWindow()
    length = windll.user32.GetWindowTextLengthW(hWnd)
    buf = create_unicode_buffer(length + 1)
    windll.user32.GetWindowTextW(hWnd, buf, length + 1)

    return buf.value if buf.value else None

def getForegroundWindowTitle_Win32UI() -> Optional[str]:
    # WARNING: This code sometimes throws an exception saying
    # "win32ui.error: No window is is in the foreground."
    # which is total nonsense. My function doesn't fail that way.
    return win32ui.GetForegroundWindow().GetWindowText()

iterations = 1_000_000

start_time = time.time()
for x in range(iterations):
    foo = getForegroundWindowTitle()
elapsed1 = time.time() - start_time
print("Elapsed 1:", elapsed1, "seconds")

start_time = time.time()
for x in range(iterations):
    foo = getForegroundWindowTitle_Win32UI()
elapsed2 = time.time() - start_time
print("Elapsed 2:", elapsed2, "seconds")

win32ui_pct_slower = ((elapsed2 / elapsed1) - 1) * 100
print("Win32UI library is", win32ui_pct_slower, "percent slower.")
Run Code Online (Sandbox Code Playgroud)

在 AMD Ryzen 3900x 上多次运行后的典型结果:

我的函数:4.5769994258880615 秒

Win32UI 库:4.8619983196258545 秒

Win32UI 库慢 6.226762715455125%。

但是,差异很小,因此您可能希望使用该库,因为它已经恢复生机(它从 2017 年起就已经死了)。但是您将不得不处理该库的奇怪的“前台没有窗口”异常,我的代码不会受到影响(请参阅基准代码中的代码注释)。

无论哪种方式......享受!


Mar*_*oma 12

以下脚本应适用于Linux,Windows和Mac.它目前仅在Linux(Ubuntu Mate Ubuntu 15.10)上测试过.

先决条件

对于Linux:

安装wnck(sudo apt-get install python-wnck在Ubuntu上,请参阅libwnck.)

对于Windows:

确保win32gui可用

对于Mac:

确保AppKit可用

剧本

#!/usr/bin/env python

"""Find the currently active window."""

import logging
import sys

logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
                    level=logging.DEBUG,
                    stream=sys.stdout)


def get_active_window():
    """
    Get the currently active window.

    Returns
    -------
    string :
        Name of the currently active window.
    """
    import sys
    active_window_name = None
    if sys.platform in ['linux', 'linux2']:
        # Alternatives: http://unix.stackexchange.com/q/38867/4784
        try:
            import wnck
        except ImportError:
            logging.info("wnck not installed")
            wnck = None
        if wnck is not None:
            screen = wnck.screen_get_default()
            screen.force_update()
            window = screen.get_active_window()
            if window is not None:
                pid = window.get_pid()
                with open("/proc/{pid}/cmdline".format(pid=pid)) as f:
                    active_window_name = f.read()
        else:
            try:
                from gi.repository import Gtk, Wnck
                gi = "Installed"
            except ImportError:
                logging.info("gi.repository not installed")
                gi = None
            if gi is not None:
                Gtk.init([])  # necessary if not using a Gtk.main() loop
                screen = Wnck.Screen.get_default()
                screen.force_update()  # recommended per Wnck documentation
                active_window = screen.get_active_window()
                pid = active_window.get_pid()
                with open("/proc/{pid}/cmdline".format(pid=pid)) as f:
                    active_window_name = f.read()
    elif sys.platform in ['Windows', 'win32', 'cygwin']:
        # http://stackoverflow.com/a/608814/562769
        import win32gui
        window = win32gui.GetForegroundWindow()
        active_window_name = win32gui.GetWindowText(window)
    elif sys.platform in ['Mac', 'darwin', 'os2', 'os2emx']:
        # http://stackoverflow.com/a/373310/562769
        from AppKit import NSWorkspace
        active_window_name = (NSWorkspace.sharedWorkspace()
                              .activeApplication()['NSApplicationName'])
    else:
        print("sys.platform={platform} is unknown. Please report."
              .format(platform=sys.platform))
        print(sys.version)
    return active_window_name

print("Active window: %s" % str(get_active_window()))
Run Code Online (Sandbox Code Playgroud)


Nun*_*dré 10

真的没有必要为这样的任务导入任何外部依赖。Python 带有一个非常简洁的外部函数接口 - ctypes,它允许本地调用 C 共享库。它甚至包括最常见的 Win32 DLL 的特定绑定。

例如,要获取foregorund 窗口的PID:

import ctypes
from ctypes import wintypes

user32 = ctypes.windll.user32

h_wnd = user32.GetForegroundWindow()
pid = wintypes.DWORD()
user32.GetWindowThreadProcessId(h_wnd, ctypes.byref(pid))
print(pid.value)
Run Code Online (Sandbox Code Playgroud)


Jam*_*son 5

对于Linux用户:提供的所有答案都需要其他模块,例如“ wx”,这些模块安装时会出现许多错误(“ pip”在构建时失败),但是我能够很容易地修改此解决方案-> 原始源代码。原始版本中存在错误(regex上为Python TypeError

import sys
import os
import subprocess
import re

def get_active_window_title():
    root = subprocess.Popen(['xprop', '-root', '_NET_ACTIVE_WINDOW'], stdout=subprocess.PIPE)
    stdout, stderr = root.communicate()

    m = re.search(b'^_NET_ACTIVE_WINDOW.* ([\w]+)$', stdout)
    if m != None:
        window_id = m.group(1)
        window = subprocess.Popen(['xprop', '-id', window_id, 'WM_NAME'], stdout=subprocess.PIPE)
        stdout, stderr = window.communicate()
    else:
        return None

    match = re.match(b"WM_NAME\(\w+\) = (?P<name>.+)$", stdout)
    if match != None:
        return match.group("name").strip(b'"')

    return None

if __name__ == "__main__":
    print(get_active_window_title())
Run Code Online (Sandbox Code Playgroud)

优点是无需附加模块即可工作。如果您希望它可以在多个平台上运行,只需更改命令和regex字符串即可根据平台获取所需的数据(在sys.platform上方显示了标准的if / else平台检测)。

附带说明:import wnck仅在与“ sudo apt-get install python-wnck”一起安装时才与python2.x一起使用,因为我使用的是python3.x,所以唯一的选择是我尚未测试的pypie。希望这对其他人有帮助。


絢瀬絵*_*瀬絵里 -10

尝试使用 wxPython:

import wx
wx.GetActiveWindow()
Run Code Online (Sandbox Code Playgroud)

  • 我不认为这就是OP所要求的。根据 wxpython 文档,GetActiveWindow“获取此应用程序的当前活动窗口”。因此,它只会返回其他 wxPython 窗口。 (7认同)