45

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

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

该管理界面是我想使用 python 来自动输入用户名和密码来捕获的。

我需要什么进口才能做到这一点?

4

10 回答 10

34

On windows, you can use the python for windows extensions (http://sourceforge.net/projects/pywin32/):

from win32gui import GetWindowText, GetForegroundWindow
print GetWindowText(GetForegroundWindow())

Below code is for python 3:

from win32gui import GetWindowText, GetForegroundWindow
print(GetWindowText(GetForegroundWindow()))

(Found this on http://scott.sherrillmix.com/blog/programmer/active-window-logger/)

于 2012-06-21T15:01:16.843 回答
21

感谢 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

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

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

享受!

Win32技术说明:

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

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

大多数(或全部?总是阅读微软的 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.")

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

我的函数:4.5769994258880615 秒

Win32UI 库:4.8619983196258545 秒

Win32UI 库慢 6.226762715455125%。

但是,差异很小,因此您可能想使用该库,因为它已经恢复了生机(它自 2017 年以来就已经死了)。但是您将不得不处理该库的奇怪的“前台没有窗口”异常,我的代码没有遇到这种情况(请参阅基准代码中的代码注释)。

不管怎样……享受吧!

于 2019-10-12T14:15:39.713 回答
21

以下脚本应该可以在 Linux、Windows 和 Mac 上运行。目前仅在 Linux (Ubuntu Mate Ubuntu 15.10) 上进行了测试。

先决条件

对于 Linux

安装wncksudo 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: https://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']:
        # https://stackoverflow.com/a/608814/562769
        import win32gui
        window = win32gui.GetForegroundWindow()
        active_window_name = win32gui.GetWindowText(window)
    elif sys.platform in ['Mac', 'darwin', 'os2', 'os2emx']:
        # https://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()))
于 2016-04-05T07:23:58.417 回答
11

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

例如获取前景窗口的 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)
于 2019-06-13T02:43:54.950 回答
10

对于 Linux 用户:提供的所有答案都需要像“wx”这样的附加模块,这些模块在安装时有很多错误(“pip”在构建时失败),但我能够很容易地修改这个解决方案 -> original source。原始版本中存在错误(Python TypeError on regex

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())

优点是它无需额外的模块即可工作。如果您希望它跨多个平台工作,只需更改命令和正则表达式字符串以根据平台获取所需的数据(使用上面显示的标准 if/else 平台检测sys.platform)。

附带说明:当使用“sudo apt-get install python-wnck”安装时,import wnck 仅适用于 python2.x,因为我使用的是 python3.x,唯一的选择是我没有测试过的 pypie。希望这对其他人有帮助。

于 2017-02-22T23:10:48.497 回答
1

这仅适用于 Windows

import win32gui
import win32process

 def get_active_executable_name():
        try:
            process_id = win32process.GetWindowThreadProcessId(
                win32gui.GetForegroundWindow()
            )
            return ".".join(psutil.Process(process_id[-1]).name().split(".")[:-1])
        except Exception as exception:
            return None

我建议查看这个答案,以使其在 linux、mac 和 windows 上运行。

于 2021-11-05T14:37:34.043 回答
1

在 X11 下的 Linux 中:

xdo_window_id = os.popen('xdotool getactivewindow').read()
print('xdo_window_id:', xdo_window_id)

将以十进制格式打印活动窗口 ID:

xdo_window_id: 67113707

注意xdotool必须先安装:

sudo apt install xdotool

注意wmctrl窗口 ID 使用十六进制格式。

于 2021-06-19T22:19:16.010 回答
0

我在linux界面(Lubuntu 20)上遇到了同样的问题。我所做的是使用 wmctrl 并使用来自 python 的 shell 命令执行它。

一、安装wmctrl sudo apt install wmctrl

然后,添加此代码:

import os
os.system('wmctrl -a "Mozilla Firefox"')

参考 wmctrl: https ://askubuntu.com/questions/21262/shell-command-to-bring-a-program-window-in-front-of-another

于 2020-09-10T03:21:41.433 回答
-1

只是想添加以防万一,我的程序有一个功能(它是我电脑照明的软件我有这个简单的几行功能:

def isRunning(process_name):
   foregroundWindow = GetWindowText(GetForegroundWindow())
   return process_name in foregroundWindow
于 2016-01-08T15:00:23.907 回答
-10

尝试使用 wxPython:

import wx
wx.GetActiveWindow()
于 2012-04-22T11:29:07.917 回答