Python自动化之win32利器pywin32

news2024/11/26 10:35:07

文章目录

  • 前言
  • 一、GUI
    • 1.1 获取、关闭窗口
    • 1.2 窗口截图
    • 1.3 创建窗口
  • 二、文件、目录
    • 2.1 查找
    • 2.2 创建
    • 2.3 复制/移动
    • 2.4 删除
    • 2.5 读取/写入
  • 三、服务
    • 3.1 查找
    • 3.2 安装
  • 四、案例
    • 4.1 自动发送微信消息
    • 4.2 Excel 操作
    • 4.3 监控文件夹
  • 参考

前言

PyWin32 是一个Python库,用于在Python脚本中访问Windows API。它提供了很多模块,允许开发者使用Python代码来操作Windows操作系统。

  • github地址:https://github.com/mhammond/pywin32

  • 安装方法

    pip install pywin32
    
  • 在线文档:

    • https://mhammond.github.io/pywin32/
    • http://timgolden.me.uk/pywin32-docs/contents.html
    • https://learn.microsoft.com/zh-cn/windows/win32/api/
  • 离线文档:

    离线文档在Python安装路径下有Lib\site-packages\PyWin32.chm 可以查找具体使用

常用模块如下:

模块名作用备注
win32api提供许多与Windows系统进行交互的函数和常量一些难以分类的api被放在这个模块
win32com提供COM对象的创建和使用方法,可以与其他应用程序(Word, Excel等)进行交互Win32中的COM对象是指遵循COM(Component Object Model)规范编写的可执行二进制代码,它以dll或exe的形式发布
win32con定义了所有的常量,是其他模块的基础
win32event提供管理事件的函数和常量,可以创建、等待和释放事件。
win32file提供文件操作的函数和常量,可以进行文件的读写、删除等操作
win32gui提供创建图形用户界面的函数和常量,可以创建窗口、按钮等控件
win32inet提供与Internet协议相关的函数和常量支持HTTP,FTP,Socket等网络协议操作
win32process提供与进程和线程相关的函数和常量,可以创建、打开和结束进程
win32registry提供注册表的操作方法,可以读取和修改Windows注册表中的数据
win32security提供Windows安全相关的函数和常量,比如权限管理、进程权限等
win32system提供系统相关的函数和常量,比如获取系统信息、关机等操作

一、GUI

1.1 获取、关闭窗口

使用 EnumWindows 可以获取所有窗口的所有控件句柄,PostMessage可以关闭窗口

import win32api
import win32con
import win32gui
import win32ui
import win32process

from PIL import Image

from collections import Counter

def _myCallback(hwnd, extra):
    hwnds, classes = extra

    if win32gui.IsWindowVisible(hwnd):
        print(hex(hwnd), win32gui.GetWindowText(hwnd), win32process.GetWindowThreadProcessId(hwnd))
        hwnds.append(hwnd)
        classes[win32gui.GetClassName(hwnd)] += 1
        # 关闭画图
        if '画图' in win32gui.GetWindowText(hwnd):
            win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
    


def testEnumWindows():
    windows = []
    classes = Counter()
    win32gui.EnumWindows(_myCallback, (windows, classes))
    print("窗口个数: %d" % len(windows))
    print(classes)

1.2 窗口截图

# 对显示窗口进行截图,注意窗口不能最小化
def windowScreenshot(windowName, windowsClass = None):
    # 根据窗口类或名字(默认)获取句柄
    # 窗口的类名可以用Visual Studio的SPY++工具获取
    hWnd = win32gui.FindWindow(windowsClass, windowName) 
    # 获取句柄窗口的大小信息
    left, top, right, bot = win32gui.GetWindowRect(hWnd)

    width = right - left
    height = bot - top
    # print(width, height, left, top)
    
    # 返回句柄窗口的设备环境,覆盖整个窗口,包括非客户区,标题栏,菜单,边框
    hWndDC = win32gui.GetWindowDC(hWnd)
    # 创建设备描述表
    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, (0, 0), win32con.SRCCOPY)


    bmpinfo = saveBitMap.GetInfo()
    bmpstr = saveBitMap.GetBitmapBits(True)
    ###生成图像
    im = Image.frombuffer('RGB',(bmpinfo['bmWidth'],bmpinfo['bmHeight']),bmpstr,'raw','BGRX')
    # im.save('./%s.jpg' % windowName)

    win32gui.DeleteObject(saveBitMap.GetHandle())
    saveDC.DeleteDC()
    mfcDC.DeleteDC()
    win32gui.ReleaseDC(hWnd, hWndDC)
    return im

1.3 创建窗口

创建最简单窗口

import win32api
import win32con
import win32gui


# 定义窗口类名和窗口标题
className = "MyWindowClass"
windowTitle = "标题Demo"

# 窗口回调函数
def wndProc(hWnd, message, wParam, lParam):
    if message == win32con.WM_DESTROY:
        win32api.PostQuitMessage(0)
        return 0
    else:
        return win32gui.DefWindowProc(hWnd, message, wParam, lParam)

# 注册窗口类
wc = win32gui.WNDCLASS()
wc.lpfnWndProc = wndProc
wc.lpszClassName = className
wc.hInstance = win32api.GetModuleHandle(None)
classAtom = win32gui.RegisterClass(wc)

# 创建窗口
style = win32con.WS_OVERLAPPEDWINDOW 
hwnd = win32gui.CreateWindow(className, windowTitle, style,
                             100, 100, 400, 300,
                             None, None, wc.hInstance, None)

# 显示窗口
win32gui.ShowWindow(hwnd, win32con.SW_SHOW)
win32gui.UpdateWindow(hwnd)

win32gui.PumpMessages()

在这里插入图片描述

二、文件、目录

2.1 查找

查找目录下所有文件目录名

import win32api
import win32con
import win32gui
import win32ui
import win32file

import os

dir = os.path.join(os.getcwd(), "*")
files = win32file.FindFilesW(dir)
fileNames = [i[8] for i in files]
print(fileNames)

2.2 创建

filename = '中文.txt'
file = win32file.CreateFile(
            filename, win32file.GENERIC_WRITE | win32file.GENERIC_READ, 0, None, win32con.OPEN_ALWAYS, 0, None
        )

directoryName = '中文目录'
win32file.CreateDirectory(directoryName, None)

2.3 复制/移动

没有发现有复制目录的api

win32api.CopyFile('1.py', 'test/1.py')
win32api.MoveFile('1.py', 'D:/1.py')

win32api.MoveFile('resource', 'test/resource')

2.4 删除

win32file.DeleteFile('D:/1.py')

win32file.RemoveDirectory('中文', None)

2.5 读取/写入

filename = '中文.txt'
f = win32file.CreateFile(
        filename,
        win32file.GENERIC_READ | win32file.GENERIC_WRITE,
        0,
        None,
        win32file.CREATE_ALWAYS,
        win32file.FILE_ATTRIBUTE_NORMAL,
        0,
    )
try:
    data = "中文测试数据".encode('utf-8')
    (res, written) = win32file.WriteFile(f, data)
    print(res, written)


    win32file.SetFilePointer(f, 0, win32file.FILE_BEGIN)
    (res, s) = win32file.ReadFile(f, len(data))
    print(res, s.decode('utf-8'))

finally:
    f.Close()

三、服务

3.1 查找

import win32con
import win32service


def EnumServices():
    resume = 0
    accessSCM = win32con.GENERIC_READ
    accessSrv = win32service.SC_MANAGER_ALL_ACCESS

    # Open Service Control Manager
    hscm = win32service.OpenSCManager(None, None, accessSCM)

    # Enumerate Service Control Manager DB

    typeFilter = win32service.SERVICE_WIN32
    stateFilter = win32service.SERVICE_STATE_ALL

    statuses = win32service.EnumServicesStatus(hscm, typeFilter, stateFilter)
    for short_name, desc, status in statuses:
        print(short_name, desc, status)


EnumServices()

3.2 安装

import win32serviceutil
import win32service
import win32event
import win32api



class MyService(win32serviceutil.ServiceFramework):
    _svc_name_ = "MyService"
    _svc_display_name_ = "My Service"

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
        self.interval = 60 # 60 seconds

    def SvcDoRun(self):
        self.ReportServiceStatus(win32service.SERVICE_RUNNING)
        while True:
            self.do_something()
            if win32event.WaitForSingleObject(self.hWaitStop, self.interval * 1000) == win32event.WAIT_OBJECT_0:
                break

    def do_something(self):
        print("do something...")
        # do your jobs here

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(MyService)

四、案例

4.1 自动发送微信消息

import win32clipboard as w
import win32con
import win32api
import win32gui

import os

# 把文字放入剪贴板
def setText(aString):
    w.OpenClipboard()
    w.EmptyClipboard()
    w.SetClipboardData(win32con.CF_UNICODETEXT,aString)
    w.CloseClipboard()
    
# 模拟ctrl+V
def ctrlV():
    win32api.keybd_event(win32con.VK_CONTROL,0,0,0) #按下ctrl
    win32api.keybd_event(ord('V'),0,0,0) #按下V
    win32api.keybd_event(ord('V'),0,win32con.KEYEVENTF_KEYUP,0)#释放V
    win32api.keybd_event(win32con.VK_CONTROL,0,win32con.KEYEVENTF_KEYUP,0)#释放ctrl
    
# 模拟alt+s
def altS():
    win32api.keybd_event(win32con.VK_MENU,0,0,0)
    win32api.keybd_event(ord('S'),0,0,0)
    win32api.keybd_event(ord('S'),0,win32con.KEYEVENTF_KEYUP,0)
    win32api.keybd_event(win32con.VK_MENU,0,win32con.KEYEVENTF_KEYUP,0)
  
# 模拟enter
def enter():
    win32api.keybd_event(win32con.VK_RETURN,0,0,0)
    win32api.keybd_event(win32con.VK_RETURN,0,win32con.KEYEVENTF_KEYUP,0)

# 模拟鼠标单击
def click():
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0,0,0)
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0,0,0)
# 移动鼠标的位置
def movePos(pos):
    win32api.SetCursorPos(pos)

if __name__=="__main__":
    
    name_list=['文件传输助手']  # 这里是要发送信息的联系人
    send_content="测试中文"    # 这里是需要发送的信息内容
    addressIconPos = (28,147) # 通讯录按钮坐标
    inputPos = (148,35) # 输入框坐标
 
    hwnd=win32gui.FindWindow("WeChatMainWndForPC", '微信') # 返回微信窗口的句柄信息
    print(hwnd)
    if hwnd is None:
        print('没找到微信窗口')
        sys.exit()
    
    win32gui.SetForegroundWindow(hwnd) # 设置为当前活动窗口
    win32gui.ShowWindow(hwnd, win32con.SW_RESTORE) # 恢复最小化的窗口
    win32gui.MoveWindow(hwnd,0,0,1000,700,True) # 将微信窗口移动到指定位置和大小
    win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 0, 0,1000,700, win32con.SWP_NOMOVE | win32con.SWP_NOSIZE)
    time.sleep(1)
    for name in name_list:
        movePos(addressIconPos)
        click()
        movePos(inputPos)
        click()
        time.sleep(1)
        setText(name)
        ctrlV()
        time.sleep(1)  # 等待联系人搜索成功
        enter()
        time.sleep(1)
        setText(send_content)
        ctrlV()
        time.sleep(1)
        altS()
        time.sleep(1)
    # win32gui.PostMessage(hwnd, win32con.WM_CLOSE, 0, 0)
  • 虚拟按键文档:https://learn.microsoft.com/zh-cn/windows/win32/inputdev/virtual-key-codes

4.2 Excel 操作

import win32com.client

# 创建Excel COM对象
excel = win32com.client.Dispatch("Excel.Application")

# 显示Excel应用程序
excel.Visible = True

# 打开Excel文件
workbook = excel.Workbooks.Open("file.xlsx")

# 选择工作表
worksheet = workbook.Worksheets("Sheet1")

# 读取单元格内容
cell_value = worksheet.Range("A1").Value

# 修改单元格内容
worksheet.Range("A1").Value = "Hello, World!"

# 保存并关闭Excel文件
workbook.Save()
workbook.Close()

4.3 监控文件夹

import win32file
import win32con
import win32api

import threading
import datetime
import time

# https://learn.microsoft.com/zh-cn/windows/win32/api/winnt/ns-winnt-file_notify_information
ACTIONS = {
    1: "该文件已添加到目录中",             
    2: "该文件已从目录中删除",           
    3: "该文件已修改",          #  这可以是时间戳或属性中的更改。
    4: "该文件已重命名,这是旧名称",  
    5: "该文件已重命名,这是新名称"   
}

logfile = 'fileLog'
            

def win32watcherThread(abspath, file_lock):
    dirHandle = win32file.CreateFile (
        abspath,
        ntsecuritycon.FILE_LIST_DIRECTORY,
        win32con.FILE_SHARE_READ | win32con.FILE_SHARE_WRITE,
        None,
        win32con.OPEN_EXISTING,
        win32con.FILE_FLAG_BACKUP_SEMANTICS | win32con.FILE_FLAG_OVERLAPPED,
        None
    )
    while True:
        results = win32file.ReadDirectoryChangesW (
            dirHandle,
            1024,
            True,
            win32con.FILE_NOTIFY_CHANGE_FILE_NAME |
                win32con.FILE_NOTIFY_CHANGE_DIR_NAME |
                win32con.FILE_NOTIFY_CHANGE_ATTRIBUTES |
                win32con.FILE_NOTIFY_CHANGE_SIZE |
                win32con.FILE_NOTIFY_CHANGE_LAST_WRITE |
                win32con.FILE_NOTIFY_CHANGE_SECURITY,
            None,
            None
        )
        for action, file in results:
            fullFilename = win32api.GetFullPathName(file)
            # fullPath = win32api.GetFullPathName(abspath)
            file_lock.acquire()
            log(abspath, fullFilename, ACTIONS.get(action, "Unknown"))
            file_lock.release()

def log(abspath, fullFileName, action):

    try:
        f = open(logfile, 'a')
        f.write(datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S ') + abspath + ' ' + fullFileName+'->' + action+'\n')
        f.close()
    except IOError:
        print('failed to open log file %s for writing', logfile)

def win32watcher(directorys):
    file_lock = threading.Lock()
    
    threads = [ threading.Thread(target=win32watcherThread,args=(abspath,file_lock,)) for abspath in directorys ]
    for thread in threads:
        thread.setDaemon(True)
        thread.start()

    try:
        while 1:
            time.sleep(3600)
    except KeyboardInterrupt:
            print("Cleaning up.")

directorys = ['test001', 'test002']
win32watcher(directorys)

参考

  1. https://mhammond.github.io/pywin32/html/com/win32com/HTML/QuickStartClientCom.html
  2. Watch a Directory for Changes
  3. 如何利用 python 向微信群里定时发送消息?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/753686.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【vue】路由的搭建以及嵌套路由

目的:学习搭建vue2项目基础的vue路由和嵌套路由 1.npm 安装 router npm install vue-router3.6.52.src下新建文件夹router文件夹以及文件index.js index.js import Vue from vue import VueRouter from "vue-router" import Home from ../views/Home.…

【Linux】- 组管理和权限管理

组管理和权限管理 1.1 Linux 组基本介绍1.2 权限的基本介绍 1.1 Linux 组基本介绍 在 linux 中的每个用户必须属于一个组,不能独立于组外。在 linux 中每个文件 有所有者、所在组、其它组的概念。 所有者所在组其它组改变用户所在的组 文件/目录 所有者 一般为文…

关于Windows 11 docker desktop 运行doris 容器时vm.max_map_count=2000000的设置问题

需要一个简单的测试环境,于是准备用docker启动一个1fe 1be的简单玩一下 如果be容器启动后再去修改 /etc/sysctl.conf sysctl -w vm.max_map_count2000000 这个参数是没用的,be仍然会启动失败 这时可以打开cmd wsl --list C:\Users\pc>wsl --list …

Docker基础——初识Docker

Docker架构 Docker 使用客户端-服务器 (C/S) 架构模式,使用远程API来管理和创建Docker容器。 Docker 客户端(Client) : Docker 客户端通过命令行或者其他工具使用 Docker SDK (https://docs.docker.com/develop/sdk/) 与 Docker 的守护进程通信。Docker 主机(Host…

MMDeploy部署YOLOX-x模型

环境搭建 本文初始环境为PyTorch 2.0.0、Python 3.8(ubuntu20.04)、Cuda 11.8 OpenMMLab基础环境 首先安装OpenMMLab基础环境,以下代码均在命令窗口下输入 pip install openmim mim install mmcv-full mim install "mmengine0.7.2"git clone https://…

太阳能供电户外视频远程监控4G无线物联网工业路由器ZR3000

太阳能供电技术常被应用于环保节能的项目中,太阳能具备节能环保、寿命长、性能稳定、维护成本低等特点,被各行各业采纳使用。大多数太阳能应用于户外,存在监控点距离较远、取电困难、宽带光纤布线成本高、环境恶劣等问题,现场还有…

ansible使用playbook剧本

目录 一、执行配置文件 1、修改hosts文件 2、编写yml脚本 3、语法检查[rootansible ~] ansible-playbook --syntax-check ansible.yml 4、预测试 5、执行命令 一、执行配置文件 Playbook配置文件使用YAML语法,具有简介明了,结构清晰等特点。Playbo…

对OpenAI重拳出击!美国政府出手「开源」ChatGPT,Altman惊慌连发3推

FTC突然对OpenAI展开调查,Altman连发3推澄清。FTC对阵OpenAI的大戏正缓缓拉开帷幕。 重磅!美国联邦贸易委员会的调查说来就来! 调查对象不是别人,正是风头正旺的OpenAI。 一封长达20页的调查要求书直接给了Sam Altman当头棒喝。…

【并发编程的艺术读书笔记】从内存图来理解java是如何执行多线程的

从内存图来理解java是如何执行多线程的 一、内存图简介 众所周知,java类中的成员变量会保存到方法区、java运行时的方法会存入栈中,随之方法中的局部变量也是存储在栈中的,引用类型(new出来的对象)存储在堆内存中。下…

【C++/嵌入式笔试面试八股】二、24.TCP三次握手四次挥手 | TCP可靠性

TCP三次握手四次挥手 64.TCP头部中有哪些信息?❤️ TCP数据报格式(左图) UDP数据报格式也放这(右图),不具体解释了。 结合三次握手四次挥手来看 端口: 区分应用层的不同应用进程 扩展:应用程序的端口号和应用程序所在主机的 IP 地址统称为 socket(套接字),IP:端口…

Linux - 安装nacos 2.1.0

安装包下载 网址为 https://github.com/alibaba/nacos/tags 点击访问 本人选择的nacos版本为2.1.0 与之对应的spring代码版本为 <spring.boot.version>2.3.12.RELEASE</spring.boot.version> <spring.cloud.version>Hoxton.SR12</spring.cloud.version…

运输层(TCP运输协议相关)

运输层 1. 运输层概述2. 端口号3. 运输层复用和分用4. 应用层常见协议使用的运输层熟知端口号5. TCP协议对比UDP协议6. TCP的流量控制7. TCP的拥塞控制7.1 慢开始算法、拥塞避免算法7.2 快重传算法7.3 快恢复算法 8. TCP超时重传时间的选择8.1 超时重传时间计算 9. TCP可靠传输…

如何在vscode中debug python代码,包括如何优雅地传入多个参数

Visiul Studio Code, 简称vscode&#xff0c;是一款轻量级代码编辑器&#xff0c;其丰富的扩展程序使得其可以方便地作为任何语言的编辑器。 本文将讲述如何在vscode中对python脚本文件进行debug。 本文主要包括debug的两种方式&#xff1a; 基本debugging(basic debugging)…

咖啡店小程序怎么做

咖啡店小程序功能介绍 咖啡店小程序是一款专为咖啡店打造的移动应用程序&#xff0c;旨在提供更便利、高效的服务体验。以下是该小程序的主要功能介绍&#xff1a; 1. 菜单浏览&#xff1a;用户可以通过小程序浏览咖啡店提供的各种咖啡、茶和小吃菜单&#xff0c;包括详细的产…

Docker基础——Centos7安装Docker

0.安装Docker Docker 分为 CE 和 EE 两大版本。CE 即社区版&#xff08;免费&#xff0c;支持周期 7 个月&#xff09;&#xff0c;EE 即企业版&#xff0c;强调安全&#xff0c;付费使用&#xff0c;支持周期 24 个月。 Docker CE 分为 stable test 和 nightly 三个更新频道…

速通sklearn库

速通sklearn库 前言 ​ 最近在复习之前学习过的知识点&#xff0c;因此想到把学过的总结一下&#xff0c;方便后面再次复习&#xff0c;所以有了这个系列。 说明 ​ 由于标题写的是“速通”&#xff0c;因此我的想法是可以让大家看完这篇文章&#xff0c;可以上手matplotlib库&…

FCPX插件-复古老电影胶片边框幻灯片照片展示介绍动画 Emotion Slides

Emotion Slides是一款fcpx插件&#xff0c;可以制作复古老电影胶片边框幻灯片照片展示介绍动画&#xff0c;完全自定义任意数量的场景&#xff0c;完全定制的控制器&#xff0c;7个独特的场景准备&#xff0c;易使用简单&#xff0c;只需拖放。 Emotion Slides插件的主要功能包…

【网络编程】传输层协议——UDP协议

文章目录 一、传输层的意义二、端口号2.1 五元组标识一个通信2.2 端口号范围划分2.3 知名端口号2.4 绑定端口号数目问题2.5 pidof & netstat命令 三、UDP协议3.1 UDP协议格式3.2 如何理解报头&#xff1f;3.3 UDP协议的特点3.4 UDP缓冲区3.5 UDP传输最大长度 一、传输层的意…

基于linux下的高并发服务器开发(第一章)- GDB调试(1)1.13

掌握一个清屏快捷键&#xff1a;CTRLL 01 / 什么是GDB 02 / 准备工作 03 / GDB 命令 -- 启动、退出、查看代码 在~/Linux/lesson08目录下有test.c文件 #include <stdio.h> #include <stdlib.h>int test(int a);int main(int argc,char* argv[]){int a,b;printf(&…

React懒加载/动态加载(Suspense +lazy())简单实例

页面嵌套 两种页面嵌套的方式&#xff0c;一种是父子组件&#xff0c;一种是懒加载1、父子组件&#xff08;可略&#xff0c;只用来做例子对比&#xff09;2、使用懒加载 两种页面嵌套的方式&#xff0c;一种是父子组件&#xff0c;一种是懒加载 1、原本需要用父子组件来实现页…