IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> UI自动化(200行python实现) -> 正文阅读

[人工智能]UI自动化(200行python实现)

实现:使用pyautogui库和pyperclip库,实际打包还涉及了OpenCV和Pillow库

自动化功能模块:(由于注释写得较多,这里不多赘述)

RPA.py

import subprocess
import time

import pyautogui
import pyperclip

pyautogui.FAILSAFE = True   # 防故障安全措施
release_list = []   # 释放键位列表,避免强行终止时有键位没有松开
start_width, start_height = pyautogui.size().width, pyautogui.size().height  # 获取启动时屏幕分辨率


def cc(coord):   # 坐标转换
    """因为指定坐标时是基于刚开始启动时的分辨率,可能与现在的分辨率不同,适应分辨率变化需要坐标转换"""
    width, height = pyautogui.size().width, pyautogui.size().height
    coord = coord.split(',')
    x, y = int(coord[0]), int(coord[1])
    real_x, real_y = int(x * width / start_width), int(y * height / start_height)
    return real_x, real_y


def read_txt(file):     # 读取txt文件
    f = open(file, 'r', encoding='utf-8')
    str_list = f.read().split('\n')
    return str_list


def mouse_click(img, click_times, click_site):   # 鼠标点击事件
    re_try = 1
    while True:
        location = pyautogui.locateCenterOnScreen('img/' + img, confidence=0.9)
        if location is not None:
            pyautogui.moveTo(location.x, location.y, 0.3, pyautogui.easeOutQuad)  # 逐渐变慢
            time.sleep(0.1)
            pyautogui.click(location.x, location.y, clicks=click_times, interval=0.2, button=click_site)
            return True
        time.sleep(0.1)
        re_try += 1
        if re_try > 3:
            print("未找到匹配图片!", img)
            return False


def input_str(string):    # 输入事件
    pyperclip.copy(string)
    pyautogui.hotkey('ctrl', 'v')


def row_work(choice, work):   # 处理一行命令
    if choice.isdigit():  # 鼠标模块
        if choice == '0':
            time.sleep(float(work))     # 等待(秒)
        elif choice == '1':
            mouse_click(work, 1, 'left')    # 左键单击
        elif choice == '2':
            mouse_click(work, 2, 'left')    # 左键双击
        elif choice == '3':
            mouse_click(work, 1, 'right')   # 右键单击
        elif choice == '4':
            mouse_click(work, 2, 'right')   # 右键双击
        elif choice == '5':
            pyautogui.scroll(int(work))     # 滚轮
        elif choice == '6':
            real_x, real_y = cc(work)
            pyautogui.dragTo(real_x, real_y, duration=0.5)    # 拖动到指定坐标
        elif choice == '7':
            real_x, real_y = cc(work)
            pyautogui.click(real_x, real_y, duration=0.2)    # 点击指定坐标
    elif choice.islower():  # 键盘模块
        if choice == 'a':
            pyautogui.press(work)   # 按一下
        elif choice == 'b':
            pyautogui.keyDown(work)  # 按住
            release_list.append(work)
        elif choice == 'c':
            pyautogui.keyUp(work)   # 松开
        elif choice == 'd':
            input_str(work)     # 键盘输入
        elif choice == 'e':
            pyautogui.write(work, interval=0.05)    # 键盘打字
        elif choice == 'cmd':
            subprocess.Popen(work, shell=True)  # 执行cmd


def main():     # 解析命令
    text = read_txt('自动化.txt')
    for row in text:
        if row:
            work_times, order_list = 1, [row]
            if row[0:2] == '重复':
                row_list = row.split('=')
                work_times = int(row_list[0][2:-1])    # 获取重复次数
                order_list = row_list[1].split('+')
            for i in range(work_times):
                for k in range(len(order_list)):
                    order = order_list[k].split('#')
                    row_work(order[0], order[1])

为了方便使用,再写一个界面调用RPA.py,进行线程管理并稍加扩展:

UI.py

import ctypes
import inspect
import threading
import time
from tkinter import Tk, Entry, StringVar, Button, DISABLED, NORMAL

import pyautogui

import RPA


def _async_raise(tid, exctype):
    """在id为tid的线程中引发异常 """
    if not inspect.isclass(exctype):
        exctype = type(exctype)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("无效的线程id")
    elif res != 1:
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc 失败")


class UI:
    def __init__(self):
        """初始化一个界面"""
        self.window = Tk()
        self.window.title('UI自动化')
        window_width, window_height = 490, 240
        self.window.geometry("%dx%d+%d+%d" % (       # 设置窗口大小 窗口居中显示
            window_width, window_height, (RPA.start_width - window_width) / 2, (RPA.start_height - window_height) / 2))
        self.window.resizable(False, False)  # 规定窗口不可缩放
        # 定义组件
        self.coord, self.cdt = StringVar(), StringVar()    # 坐标,倒计时
        self.cdt.set('2')
        self.save_input, self.t, self.last_id = '', None, 0
        self.close, self.exit_t1 = False, False      # 主窗口退出的标志,t1退出标志
        entry1 = Entry(self.window, width=10, textvariable=self.coord, state="readonly",
                       fg='blue', font=('宋体', 29), justify='center')
        self.entry2 = Entry(self.window, width=10, textvariable=self.cdt, font=('宋体', 29),
                            fg='red', justify='center')
        self.button1 = Button(self.window, width=15, height=3, text='获取光标位置', font=('黑体', 15),
                              bg='violet', command=self.run1)
        self.button2 = Button(self.window, width=15, height=3, text='定时开始(秒)', font=('黑体', 15),
                              bg='cyan', command=self.run2)
        self.button3 = Button(self.window, width=38, height=3, text='终止', font=('黑体', 15), bg="pink",
                              command=self.stop_thread)
        # 设置界面布局
        entry1.grid(row=0, column=0, columnspan=2)
        self.entry2.grid(row=0, column=3, columnspan=2)
        self.button1.grid(row=1, column=0, columnspan=2)
        self.button2.grid(row=1, column=3, columnspan=2)
        self.button3.grid(row=2, column=1, columnspan=3)
        self.window.protocol("WM_DELETE_WINDOW", self.close_ui)     # 拦截窗体关闭事件
        self.window.mainloop()

    def run1(self):
        t1 = threading.Thread(target=self.update_location)
        t1.setDaemon(True)
        t1.start()

    def run2(self):
        get_input = self.entry2.get()
        if get_input and get_input.isdigit():  # 数据检测
            self.save_input = get_input
            self.t = threading.Thread(target=self.execute)
            self.t.setDaemon(True)
            self.t.start()

    def stop_thread(self):
        self.exit_t1 = True     # 终止线程t1
        if self.t and self.t.ident != self.last_id:
            _async_raise(self.t.ident, SystemExit)  # 终止线程t
            if not self.close:
                self.button2["text"] = "定时(秒)"
                self.button2['state'] = NORMAL
                self.last_id = self.t.ident
                self.window.after(0, self.cdt.set(self.save_input))  # 恢复定时倒计时
        if not self.close:
            self.button1["text"] = "获取光标位置"
            self.button1['state'] = NORMAL
            self.window.after(0, self.coord.set(''))  # 清空坐标输入框
        RPA.release_list = list(set(RPA.release_list))     # 列表去重
        for key in RPA.release_list:    # 释放键位,防止卡键
            pyautogui.keyUp(key)
        RPA.release_list.clear()    # 清空列表

    def update_location(self):  # 更新光标位置
        self.exit_t1 = False
        self.button1['state'] = DISABLED
        self.button1["text"] = "点击终止取消"
        while not self.close and not self.exit_t1:
            self.get_location()
            time.sleep(0.05)     # 如果不设为守护线程,更新速度太快会使直接退出时子线程t1无法关闭(主线程和子线程间切换太快)

    def execute(self):  # 执行命令函数
        self.button2['state'] = DISABLED
        second = int(self.save_input)
        while second:
            time.sleep(1)
            second -= 1
            self.window.after(0, self.cdt.set(str(second)))
        self.button2["text"] = "执行中"
        try:
            RPA.main()
        except Exception as e:  # 如果执行出错,避免卡死,捕获一下异常
            pyautogui.alert(text=str(e), title='出错提示')  # 弹窗显示错误
        self.window.after(0, self.cdt.set(self.save_input))     # 恢复定时倒计时
        self.last_id = self.t.ident  # 更新last_id
        self.button2["text"] = "定时(秒)"
        self.button2['state'] = NORMAL

    def get_location(self):     # 获取光标位置
        location = pyautogui.position()
        location = str(location.x) + "," + str(location.y)
        self.window.after(0, self.coord.set(location))

    def close_ui(self):    # 关闭前先隐藏主窗口,预留几秒给主线程关闭子线程的时间,再关闭主窗口
        self.close = True   # 关闭子线程t1
        self.window.withdraw()  # 隐藏窗口
        self.stop_thread()  # 关闭子线程t
        time.sleep(2)   # 等待t线程完全退出
        self.window.destroy()


if __name__ == '__main__':
    UI()

打包成exe,最终效果图:

?文件目录结构:

?阅读使用文档即可会编写指令。

UI自动化下载

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-01-04 13:26:12  更:2022-01-04 13:27:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 22:43:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码