Python开发游戏自动化后台脚本——实例分享

说明

获取窗口句柄

寻找标题为title的窗口,激活该窗口并置于x_coor, y_coor处,title可利用visual studio的spy++.exe查看;SWP_NOSIZE指定了窗口大小不变

def get_winds(self, title: str):`    `"""`    `@description : 获取游戏句柄 ,并把游戏窗口置顶并激活窗口`    `---------`    `@param : 窗口名`    `-------`    `@Returns : 窗口句柄`    `-------`    `"""`    `# self.__handle = win32gui.FindWindowEx(0, 0, "Qt5QWindowIcon", "MuMu模拟器")`    `self.__handle = windll.user32.FindWindowW(None, title)`    `self.__classname = win32gui.GetClassName(self.__handle)`    `# print(self.__classname)`    `if self.__classname == 'Qt5QWindowIcon':`        `self.__mainhandle = win32gui.FindWindowEx(self.__handle, 0, "Qt5QWindowIcon", "MainWindowWindow")`        `# print(self.__mainhandle)`        `self.__centerhandle = win32gui.FindWindowEx(self.__mainhandle, 0, "Qt5QWindowIcon", "CenterWidgetWindow")`        `# print(self.__centerhandle)`        `self.__renderhandle = win32gui.FindWindowEx(self.__centerhandle, 0, "Qt5QWindowIcon", "RenderWindowWindow")`        `# print(self.__renderhandle)`        `self.__clickhandle = self.__renderhandle`    `else:`        `self.__clickhandle = self.__handle`    `# self.__subhandle = win32gui.FindWindowEx(self.__renderhandle, 0, "subWin", "sub")`    `# print(self.__subhandle)`    `# self.__subsubhandle = win32gui.FindWindowEx(self.__subhandle, 0, "subWin", "sub")`    `# print(self.__subsubhandle)`    `# win32gui.ShowWindow(hwnd1, win32con.SW_RESTORE)`    `# print(win32gui.GetWindowRect(hwnd1))`    `win32gui.SetWindowPos(self.__handle, win32con.HWND_TOP, x_coor, y_coor, 0, 0, win32con.SWP_SHOWWINDOW | win32con.SWP_NOSIZE)`    `print(self.__clickhandle)`    `return self.__handle``   

获得后台窗口截图

窗口上方有39个像素的边框,左、右、下则有8个像素的边框

def get_src(self):`    `"""`    `@description : 获得后台窗口截图`    `---------`    `@param : None`    `-------`    `@Returns : None`    `-------`    `"""``   `    `left, top, right, bot = win32gui.GetWindowRect(self.__handle)`    `#Remove border around window (8 pixels on each side)`    `bl = 8`    `#Remove border on top`    `bt = 39``   `    `width = int((right - left + 1) * scale) - 2 * bl`    `height = int((bot - top + 1) * scale) - bt - bl`    `# 返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框`    `hWndDC = win32gui.GetWindowDC(self.__handle)`    `# 创建设备描述表`    `mfcDC = win32ui.CreateDCFromHandle(hWndDC)`    `# 创建内存设备描述表`    `saveDC = mfcDC.CreateCompatibleDC()`    `# 创建位图对象准备保存图片`    `saveBitMap = win32ui.CreateBitmap()`    `# 为bitmap开辟存储空间`    `saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)`    `# 将截图保存到saveBitMap中`    `saveDC.SelectObject(saveBitMap)`    `# 保存bitmap到内存设备描述表`    `saveDC.BitBlt((0, 0), (width, height), mfcDC, (bl, bt), win32con.SRCCOPY)`    `###获取位图信息`    `bmpinfo = saveBitMap.GetInfo()`    `bmpstr = saveBitMap.GetBitmapBits(True)`    `###生成图像`    `im_PIL = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1)`    `# 内存释放`    `win32gui.DeleteObject(saveBitMap.GetHandle())`    `saveDC.DeleteDC()`    `mfcDC.DeleteDC()`    `win32gui.ReleaseDC(self.__handle, hWndDC)`    `###PrintWindow成功,保存到文件,显示到屏幕`    `im_PIL.save("src.jpg")  # 保存`    `# im_PIL.show()  # 显示``   

数字识别

依赖项——Tesseract OCR
下载并添加至系统环境变量

注意:这里将ocr识别范围限定为0-9的数字以提高准确率
截取范围为src.jpg中左上(x1,y1)到右下(x2,y2)的矩形区域

def get_num(self, x1, y1, x2, y2):`    `"""`    `@description : 获取屏幕截图中的数字`    `---------`    `@param : 截图中需要截取的含数字部分边界`    `-------`    `@Returns : num:int`    `-------`    `"""`        `    img = Image.open("src.jpg")`    `num_img = img.crop((x1, y1, x2, y2))`    `num_img = ImageOps.invert(num_img)`    `num = pytesseract.image_to_string(num_img, lang="eng",`                                          `config='--psm 6 --oem 3 -c tessedit_char_whitelist=0123456789').strip()`    `# num = pytesseract.image_to_string(num_img, lang="eng")`    `try:`        `print("数量为", int(num))`        `return int(num)`    `except:`        `print("未检测到数字")`        `return 0``   

识别并点击图片位置

所需识别的图片模板事先准备好并放在同一目录下,输入图片文件路径
这里confidence设置为0.9

def mouse_click_image(self, name : str, times = 0.5):`    `"""`    `@Description : 鼠标左键点击识别到的图片位置`    `---------`    `@Args : name:输入图片名; times:单击后延时`    `-------`    `@Returns : None`    `-------`    `"""`    `try:`        `result = self.recognize(name)`        `if result is None or result['confidence'] < 0.9:`            `print("No results!")`        `else:`            `print(result['result'][0] + x_coor * scale + 8, " ",result['result'][1] + y_coor * scale + 39)`            `self.mouse_click(result['result'][0] + x_coor * scale + 8, result['result'][1] + y_coor * scale + 39)`    `except:`        `raise Exception("error")``   

后台文字输入

def type_str(self, msg: str):`    `"""`    `@Description : 打字`    `---------`    `@Args : msg:目标字符`    `-------`    `@Returns : None`    `-------`    `"""`    `for i in msg:`        `self.__PostMessageW(self.__handle, win32con.WM_CHAR, ord(i), 0)``   

完整代码

GITEE网址: 项目-AutoClick.https://gitee.com/yaadon/auto-click

#!/usr/bin/env python``# -*- encoding: utf-8 -*-``'''``@File    :   AutoClick.py``@Time    :   2021/10/09 15:10:01``@Author  :   Yaadon` `'''``   ``# here put the import lib``import win32con``import win32gui``import win32ui``import time``# import threading``import numpy as np``import os``from PIL import Image``from PIL import ImageOps``import aircv as ac``import pytesseract``from ctypes import windll, byref``from ctypes.wintypes import HWND, POINT``import string``# import sys``# import cv2``# from memory_pic import *``# import win32api``# import autopy``# from PIL import ImageGrab``   ``scale = 1.25 # 电脑的缩放比例``radius = 5 # 随机半径``x_coor = 10 # 窗口位置``y_coor = 10 # 窗口位置``   ``class AutoClick():`    `"""`    `@description  :自动点击类,包含后台截图、图像匹配`    `---------`    `@param  :`    `-------`    `@Returns  :`    `-------`    `"""`    `    __PostMessageW = windll.user32.PostMessageW`    `__SendMessageW = windll.user32.SendMessageW`    `__MapVirtualKeyW = windll.user32.MapVirtualKeyW`    `__VkKeyScanA = windll.user32.VkKeyScanA`    `__ClientToScreen = windll.user32.ClientToScreen``   `    `__WM_KEYDOWN = 0x100`    `__WM_KEYUP = 0x101`    `__WM_MOUSEMOVE = 0x0200`    `__WM_LBUTTONDOWN = 0x0201`    `__WM_LBUTTONUP = 0x202`    `__WM_MOUSEWHEEL = 0x020A`    `__WHEEL_DELTA = 120`    `__WM_SETCURSOR = 0x20`    `__WM_MOUSEACTIVATE = 0x21``   `    `__HTCLIENT = 1`    `__MA_ACTIVATE = 1``   `    `__VkCode = {`        `"back":  0x08,`        `"tab":  0x09,`        `"return":  0x0D,`        `"shift":  0x10,`        `"control":  0x11,`        `"menu":  0x12,`        `"pause":  0x13,`        `"capital":  0x14,`        `"escape":  0x1B,`        `"space":  0x20,`        `"end":  0x23,`        `"home":  0x24,`        `"left":  0x25,`        `"up":  0x26,`        `"right":  0x27,`        `"down":  0x28,`        `"print":  0x2A,`        `"snapshot":  0x2C,`        `"insert":  0x2D,`        `"delete":  0x2E,`        `"lwin":  0x5B,`        `"rwin":  0x5C,`        `"numpad0":  0x60,`        `"numpad1":  0x61,`        `"numpad2":  0x62,`        `"numpad3":  0x63,`        `"numpad4":  0x64,`        `"numpad5":  0x65,`        `"numpad6":  0x66,`        `"numpad7":  0x67,`        `"numpad8":  0x68,`        `"numpad9":  0x69,`        `"multiply":  0x6A,`        `"add":  0x6B,`        `"separator":  0x6C,`        `"subtract":  0x6D,`        `"decimal":  0x6E,`        `"divide":  0x6F,`        `"f1":  0x70,`        `"f2":  0x71,`        `"f3":  0x72,`        `"f4":  0x73,`        `"f5":  0x74,`        `"f6":  0x75,`        `"f7":  0x76,`        `"f8":  0x77,`        `"f9":  0x78,`        `"f10":  0x79,`        `"f11":  0x7A,`        `"f12":  0x7B,`        `"numlock":  0x90,`        `"scroll":  0x91,`        `"lshift":  0xA0,`        `"rshift":  0xA1,`        `"lcontrol":  0xA2,`        `"rcontrol":  0xA3,`        `"lmenu":  0xA4,`        `"rmenu":  0XA5`    `}``   `    `def __get_virtual_keycode(self, key: str):`        `"""根据按键名获取虚拟按键码``   `        `Args:`            `key (str): 按键名``   `        `Returns:`            `int: 虚拟按键码`        `"""`        `if len(key) == 1 and key in string.printable:`            `# https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-vkkeyscana`            `return self.__VkKeyScanA(ord(key)) & 0xff`        `else:`            `return self.__VkCode[key]``   ``   `    `def __key_down(self, handle: HWND, key: str):`        `"""按下指定按键``   `        `Args:`            `handle (HWND): 窗口句柄`            `key (str): 按键名`        `"""`        `vk_code = self.__get_virtual_keycode(key)`        `scan_code = self.__MapVirtualKeyW(vk_code, 0)`        `# https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keydown`        `wparam = vk_code`        `lparam = (scan_code << 16) | 1`        `self.__PostMessageW(handle, self.__WM_KEYDOWN, wparam, lparam)``   ``   `    `def __key_up(self, handle: HWND, key: str):`        `"""放开指定按键``   `        `Args:`            `handle (HWND): 窗口句柄`            `key (str): 按键名`        `"""`        `vk_code = self.__get_virtual_keycode(key)`        `scan_code = self.__MapVirtualKeyW(vk_code, 0)`        `# https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-keyup`        `wparam = vk_code`        `lparam = (scan_code << 16) | 0XC0000001`        `self.__PostMessageW(handle, self.__WM_KEYUP, wparam, lparam)``   ``   `    `def __activate_mouse(self, handle: HWND):`        `"""`        `@Description : 激活窗口接受鼠标消息`        `---------`        `@Args : handle (HWND): 窗口句柄`        `-------`        `@Returns :``        -------`        `"""`        `# https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mouseactivate`        `lparam = (self.__WM_LBUTTONDOWN << 16) | self.__HTCLIENT`        `self.__SendMessageW(handle, self.__WM_MOUSEACTIVATE, self.__handle, lparam)`    `   `    `def __set_cursor(self, handle: HWND, msg):`        `"""`        `@Description : Sent to a window if the mouse causes the cursor to move within a window and mouse input is not captured`        `---------`        `@Args : handle (HWND): 窗口句柄, msg : setcursor消息`        `-------`        `@Returns :``        -------`        `"""`        `# https://docs.microsoft.com/en-us/windows/win32/menurc/wm-setcursor`        `lparam = (msg << 16) | self.__HTCLIENT`        `self.__SendMessageW(handle, self.__WM_SETCURSOR, handle, lparam)``   `    `    def __move_to(self, handle: HWND, x: int, y: int):`        `"""移动鼠标到坐标(x, y)``   `        `Args:`            `handle (HWND): 窗口句柄`            `x (int): 横坐标`            `y (int): 纵坐标`        `"""`        `# https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mousemove`        `wparam = 0`        `lparam = y << 16 | x`        `self.__PostMessageW(handle, self.__WM_MOUSEMOVE, wparam, lparam)``   ``   `    `def __left_down(self, handle: HWND, x: int, y: int):`        `"""在坐标(x, y)按下鼠标左键``   `        `Args:`            `handle (HWND): 窗口句柄`            `x (int): 横坐标`            `y (int): 纵坐标`        `"""`        `# https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttondown`        `wparam = 0x001 # MK_LBUTTON`        `lparam = y << 16 | x`        `self.__PostMessageW(handle, self.__WM_LBUTTONDOWN, wparam, lparam)``   ``   `    `def __left_up(self, handle: HWND, x: int, y: int):`        `"""在坐标(x, y)放开鼠标左键``   `        `Args:`            `handle (HWND): 窗口句柄`            `x (int): 横坐标`            `y (int): 纵坐标`        `"""`        `# https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-lbuttonup`        `wparam = 0`        `lparam = y << 16 | x`        `self.__PostMessageW(handle, self.__WM_LBUTTONUP, wparam, lparam)``   ``   `    `def __scroll(self, handle: HWND, delta: int, x: int, y: int):`        `"""在坐标(x, y)滚动鼠标滚轮``   `        `Args:`            `handle (HWND): 窗口句柄`            `delta (int): 为正向上滚动,为负向下滚动`            `x (int): 横坐标`            `y (int): 纵坐标`        `"""`        `self.__move_to(handle, x, y)`        `# https://docs.microsoft.com/en-us/windows/win32/inputdev/wm-mousewheel`        `wparam = delta << 16`        `p = POINT(x, y)`        `self.__ClientToScreen(handle, byref(p))`        `lparam = p.y << 16 | p.x`        `self.__PostMessageW(handle, self.__WM_MOUSEWHEEL, wparam, lparam)``   ``   `    `def __scroll_up(self, handle: HWND, x: int, y: int):`        `"""在坐标(x, y)向上滚动鼠标滚轮``   `        `Args:`            `handle (HWND): 窗口句柄`            `x (int): 横坐标`            `y (int): 纵坐标`        `"""`        `self.__scroll(handle, self.__WHEEL_DELTA, x, y)``   ``   `    `def __scroll_down(self, handle: HWND, x: int, y: int):`        `"""在坐标(x, y)向下滚动鼠标滚轮``   `        `Args:`            `handle (HWND): 窗口句柄`            `x (int): 横坐标`            `y (int): 纵坐标`        `"""`        `self.__scroll(handle, -self.__WHEEL_DELTA, x, y)``   ``   `    `def get_winds(self, title: str):`        `"""`        `@description : 获取游戏句柄 ,并把游戏窗口置顶并激活窗口`        `---------`        `@param : 窗口名`        `-------`        `@Returns : 窗口句柄`        `-------`        `"""`        `# self.__handle = win32gui.FindWindowEx(0, 0, "Qt5QWindowIcon", "MuMu模拟器")`        `self.__handle = windll.user32.FindWindowW(None, title)`        `self.__classname = win32gui.GetClassName(self.__handle)`        `# print(self.__classname)`        `if self.__classname == 'Qt5QWindowIcon':`            `self.__mainhandle = win32gui.FindWindowEx(self.__handle, 0, "Qt5QWindowIcon", "MainWindowWindow")`            `# print(self.__mainhandle)`            `self.__centerhandle = win32gui.FindWindowEx(self.__mainhandle, 0, "Qt5QWindowIcon", "CenterWidgetWindow")`            `# print(self.__centerhandle)`            `self.__renderhandle = win32gui.FindWindowEx(self.__centerhandle, 0, "Qt5QWindowIcon", "RenderWindowWindow")`            `# print(self.__renderhandle)`            `self.__clickhandle = self.__renderhandle`        `else:`            `self.__clickhandle = self.__handle`        `# self.__subhandle = win32gui.FindWindowEx(self.__renderhandle, 0, "subWin", "sub")`        `# print(self.__subhandle)`        `# self.__subsubhandle = win32gui.FindWindowEx(self.__subhandle, 0, "subWin", "sub")`        `# print(self.__subsubhandle)`        `# win32gui.ShowWindow(hwnd1, win32con.SW_RESTORE)`        `# print(win32gui.GetWindowRect(hwnd1))`        `win32gui.SetWindowPos(self.__handle, win32con.HWND_TOP, x_coor, y_coor, 0, 0, win32con.SWP_SHOWWINDOW | win32con.SWP_NOSIZE)`        `print(self.__clickhandle)`        `return self.__handle`    `   `    `def get_src(self):`        `"""`        `@description : 获得后台窗口截图`        `---------`        `@param : None`        `-------`        `@Returns : None`        `-------`        `"""``   `        `left, top, right, bot = win32gui.GetWindowRect(self.__handle)`        `#Remove border around window (8 pixels on each side)`        `bl = 8`        `#Remove border on top`        `bt = 39``   `        `width = int((right - left + 1) * scale) - 2 * bl`        `height = int((bot - top + 1) * scale) - bt - bl`        `# 返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框`        `hWndDC = win32gui.GetWindowDC(self.__handle)`        `# 创建设备描述表`        `mfcDC = win32ui.CreateDCFromHandle(hWndDC)`        `# 创建内存设备描述表`        `saveDC = mfcDC.CreateCompatibleDC()`        `# 创建位图对象准备保存图片`        `saveBitMap = win32ui.CreateBitmap()`        `# 为bitmap开辟存储空间`        `saveBitMap.CreateCompatibleBitmap(mfcDC, width, height)`        `# 将截图保存到saveBitMap中`        `saveDC.SelectObject(saveBitMap)`        `# 保存bitmap到内存设备描述表`        `saveDC.BitBlt((0, 0), (width, height), mfcDC, (bl, bt), win32con.SRCCOPY)`        `###获取位图信息`        `bmpinfo = saveBitMap.GetInfo()`        `bmpstr = saveBitMap.GetBitmapBits(True)`        `###生成图像`        `im_PIL = Image.frombuffer('RGB', (bmpinfo['bmWidth'], bmpinfo['bmHeight']), bmpstr, 'raw', 'BGRX', 0, 1)`        `# 内存释放`        `win32gui.DeleteObject(saveBitMap.GetHandle())`        `saveDC.DeleteDC()`        `mfcDC.DeleteDC()`        `win32gui.ReleaseDC(self.__handle, hWndDC)`        `###PrintWindow成功,保存到文件,显示到屏幕`        `im_PIL.save("src.jpg")  # 保存`        `# im_PIL.show()  # 显示`    `   `    `   `    `def recognize(self, objs):`        `"""`        `@description : 图像识别之模板匹配`        `---------`        `@param : 需要匹配的模板名`        `-------`        `@Returns : 将传进来的图片和全屏截图匹配如果找到就返回图像在屏幕的坐标 否则返回None`        `-------`        `"""`        `        imobj = ac.imread(objs)`        `imsrc = ac.imread('%s\\src.jpg' % os.getcwd())`        `pos = ac.find_template(imsrc, imobj, 0.5)`        `return pos``   ``   `    `def mouse_click(self, x, y, times=0.5):`        `"""`        `@description : 单击左键`        `---------`        `@param : 位置坐标x,y 单击后延时times(s)`        `-------`        `@Returns :``        -------`        `"""`        `# self.__set_cursor(self.__clickhandle, self.__WM_MOUSEACTIVATE)`        `# self.__move_to(self.__clickhandle, int(x / scale), int(y / scale))`        `# self.__activate_mouse(self.__clickhandle)`        `# self.__set_cursor(self.__clickhandle, self.__WM_LBUTTONDOWN)`        `self.__left_down(self.__clickhandle, int(x / scale), int(y / scale))`        `self.__move_to(self.__clickhandle, int(x / scale), int(y / scale))`        `self.__left_up(self.__clickhandle, int(x / scale), int(y / scale))`        `time.sleep(times)`    `   `    `def mouse_click_image(self, name : str, times = 0.5):`        `"""`        `@Description : 鼠标左键点击识别到的图片位置`        `---------`        `@Args : name:输入图片名; times:单击后延时`        `-------`        `@Returns : None`        `-------`        `"""`        `try:`            `result = self.recognize(name)`            `if result is None or result['confidence'] < 0.9:`                `print("No results!")`            `else:`                `print(result['result'][0] + x_coor * scale + 8, " ",result['result'][1] + y_coor * scale + 39)`                `self.mouse_click(result['result'][0] + x_coor * scale + 8, result['result'][1] + y_coor * scale + 39)`        `except:`            `raise Exception("error")``   `    `    def mouse_click_radius(self, x, y, times=0.5):`        `"""`        `@description : 在范围内随机位置单击(防检测)`        `---------`        `@param : 位置坐标x,y 单击后延时times(s)`        `-------`        `@Returns :``        -------`        `"""`        `        random_x = np.random.randint(-radius, radius)`        `random_y = np.random.randint(-radius, radius)`        `self.mouse_click(x + random_x, y + random_y)`        `# self.__left_down(self.__clickhandle, int((x + random_x) / scale), int((y + random_y) / scale))`        `# time.sleep(0.1)`        `# self.__left_up(self.__clickhandle, int((x + random_x) / scale), int((y + random_y) / scale))`        `time.sleep(times)``   ``   `    `def push_key(self, key: str, times = 1):`        `"""`        `@Description : 按键`        `---------`        `@Args : key:按键 times:按下改键后距松开的延时`        `-------`        `@Returns : None`        `-------`        `"""`        `self.__key_down(self.__clickhandle, key)`        `time.sleep(times)`        `self.__key_up(self.__clickhandle, key)`        `time.sleep(0.5)`    `   `    `def type_str(self, msg: str):`        `"""`        `@Description : 打字`        `---------`        `@Args : msg:目标字符`        `-------`        `@Returns : None`        `-------`        `"""`        `for i in msg:`            `self.__PostMessageW(self.__clickhandle, win32con.WM_CHAR, ord(i), 0)``   ``   ``if __name__ == '__main__':`    `click = AutoClick()`    `click.get_winds("微信")`    `click.get_src()`    `# click.mouse_click(254, 536)`    `click.mouse_click_image('test.png')`    `# click.mouse_click(1086, 269) # 输入框`    `# click.mouse_click(237, 211) # 输入框`    `# click.mouse_click(1228, 201) # 输入框`    `# click.type_str("123木头人abc")``   

至此,就是我在学习后台自动化过程中查阅到的一篇完整代码。代码作者和下载网址均附上。

其中有一些小细节我展开说一下:

1.如果窗口中有多个图像与目标相符,如何进行匹配?

可以使用find_all_template函数。

代码如下:

import aircv as ac  ``# 读取源图像和模板图像`  `im_src = ac.imread('source_image.png')`  `im_template = ac.imread('template_image.png')  ``# 查找所有匹配的区域`  `matches = ac.find_all_template(im_src, im_template, threshold=0.5)  ``# 遍历匹配结果并标记匹配区域`  `for match in matches:  ``     x, y = match['result']   ``     w, h = match['rectangle'][2][0] - match['rectangle'][0][0], match['rectangle'][2][1] - match['rectangle'][0][1]   ``     ac.rectangle(im_src, (x, y), (x+w, y+h), (0, 255, 0), 2)   ``# 显示标记后的图像`  `ac.imshow(im_src)`  `ac.waitkey(0)

2.如何在后台窗口进行点击?

这个问题可能有点呆,我们这几讲以及上面的代码不就是讲的这个么?

我们看上面的代码click.mouse_click(1086, 269),是不是必须得先给定坐标?那是因为click的底层逻辑move_to以及left_down、left_up都是需要PostMessageW来传递坐标信息才能完成的。也就是要进行鼠标点击,必须获得后台窗口虚拟鼠标的位置。

那么问题就变成了,我们如何获得后台窗口虚拟鼠标的位置?

文心一言的回答

方法一:文心一言都知道,pyautogui只能获取前台窗口的鼠标位置。

方法二:用win32api.GetCursorPos()获得鼠标坐标。结论:也是前台鼠标位置。

方法三:ChatGPT让我安裝一個鼠標鉤子來監視鼠標消息。在鼠標鉤子回調函數中,處理WM_MOUSEMOVE消息並提取鼠標位置信息。

钩子怎么写我就先不放了,如果有需要的我可以单独开一讲。直接说结论吧,——还是不行

方法四:参照https://www.cnpython.com/qa/1403927的回答,尝试Retrieves the cursor position for the last message retrieved by the GetMessage function.因为win32gui里没有GetMessage,我们就自己造一个。

    `def move_to(self, x, y, times=0.5):`        `"""`        `@description : 移动鼠标`        `---------`        `@param : 位置坐标x,y 单击后延时times(s)`        `-------`        `@Returns :`        `-------`        `"""`        `global xx,yy`        `xx=x`        `yy=y`        `self.__move_to(self.__clickhandle, int(x), int(y))`        `time.sleep(times)`

在move_to里加了一对全局变量xx,yy,把鼠标位置坐标存在变量里,再写一个单击的函数:

    `def leftclick(self, times=0.5):`        `"""`        `@description : 单击左键`        `---------`        `@param : 单击后延时times(s)`        `-------`        `@Returns :`        `-------`        `"""``   `        `self.left_down(self.__clickhandle, int(xx), int(yy))`        `time.sleep(times)`        `self.left_up(self.__clickhandle, int(xx), int(yy))`        `time.sleep(times)`

注意这个函数只能在PostMessage后面才能得到鼠标坐标。当然也是没办法,我自己想了一个折中的办法。如果有更好的解决方案也请私信我。

点击下方安全链接前往获取

CSDN大礼包:《Python入门&进阶学习资源包》免费分享

👉Python实战案例👈

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

图片

图片

👉Python书籍和视频合集👈

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

图片

👉Python副业创收路线👈

图片

这些资料都是非常不错的,朋友们如果有需要《Python学习路线&学习资料》,点击下方安全链接前往获取

CSDN大礼包:《Python入门&进阶学习资源包》免费分享

本文转自 网络,如有侵权,请联系删除。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值