我想使用 python 在屏幕上获取活动窗口。
比如路由器的管理界面,输入用户名和密码为admin
该管理界面是我想使用 python 来自动输入用户名和密码来捕获的。
我需要什么进口才能做到这一点?
我想使用 python 在屏幕上获取活动窗口。
比如路由器的管理界面,输入用户名和密码为admin
该管理界面是我想使用 python 来自动输入用户名和密码来捕获的。
我需要什么进口才能做到这一点?
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/)
感谢 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 Optional
and -> 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 年以来就已经死了)。但是您将不得不处理该库的奇怪的“前台没有窗口”异常,我的代码没有遇到这种情况(请参阅基准代码中的代码注释)。
不管怎样……享受吧!
以下脚本应该可以在 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: 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()))
对于这样的任务,确实不需要导入任何外部依赖项。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)
对于 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。希望这对其他人有帮助。
这仅适用于 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 上运行。
在 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 使用十六进制格式。
我在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
只是想添加以防万一,我的程序有一个功能(它是我电脑照明的软件我有这个简单的几行功能:
def isRunning(process_name):
foregroundWindow = GetWindowText(GetForegroundWindow())
return process_name in foregroundWindow
尝试使用 wxPython:
import wx
wx.GetActiveWindow()