说明:前面的部分用于打开外部程序.exe;win32gui用于关闭窗口程序(显示最大化最小化)
Python调用(运行)外部程序 2019/3/7
在Python中可在脚本中直接使用其他脚本或程序
1 使用os.system(command)运行其他程序
参数
command 要执行的命令,相当于在Windows的cmd窗口中输入的命令。
如果要向程序或者脚本传递参数,可以使用空格分隔程序及多个参数。
实例:
import os,sys
os.system('notepad') # 使用os.system()函数打开记事本程序
os.system('notepad python.txt')# 向记事本传递参数,打开python.txt文件
os.system('start "" /d "C:\\Users\\Administrator\\AppData\\Roaming\\Goldminer3\\" /wait
"goldminer3.exe" ''--username=131628911xx --password=xxxx')
实例1.1:
def test():
#base_dir=os.path.dirname("C:\\Users\\Administrator\\AppData\\Roaming\\Goldminer3\\")
#sys.path.append(base_dir) #临时修改环境变量
currrent_path=os.getcwd()
print('1.current_path=',os.getcwd())#D:\PycharmProjects\test_py36
os.chdir("C:\\Users\\Administrator\\AppData\\Roaming\\Goldminer3\\")#必须
print('2.current_path=',os.getcwd())
# C:\Users\Administrator\AppData\Roaming\Goldminer3
os.system('goldminer3.exe --username=13162891176 --password=tcy-1974')
os.chdir(currrent_path) #改变工作目录
test()
显示结果:
1.current_path= D:\PycharmProjects\test_py36
2.current_path= C:\Users\Administrator\AppData\Roaming\Goldminer3
[main 下午1:22:38] updatesetState idle
[main 下午1:22:38] BackendInit { version: '3.10.0',
commit: '10706b5ff1e4441304cd410756328c5d43e9b548' }
...
[main 下午1:23:24] Backendquit
3.current_path= D:\PycharmProjects\test_py36
2 ShellExecute(hwnd, op , file , params , dir , bShow )相当于在资源管理器中双击文件图标一样:
参数
hwnd:父窗口的句柄,如果没有父窗口,则为0。
op: 要进行的操作,为“open”、“print”或者为空。
file:要运行的程序,或者打开的脚本。
params:要向程序传递的参数,如果打开的为文件,则为空。
dir: 程序初始化的目录。
bShow: 是否显示窗口。
实例2.1:
import win32api
win32api.ShellExecute(0, 'open', 'notepad.exe', '','',0)#打开记事本后台运行
win32api.ShellExecute(0, 'open', 'notepad.exe', '','',1)#前台运行
win32api.ShellExecute(0, 'open', 'notepad.exe', 'python.txt','',1)# 向记事本传递参数,打开python.txt
win32api.ShellExecute(0, 'open', 'http://www.python.org', '','',1)# 在默认浏览器中打开网站
win32api.ShellExecute(0, 'open', 'E:\\song.wma', '','',1) # 在默认的媒体播放器中播放E:\song.wma
win32api.ShellExecute(0, 'open', 'E:\\book\\code\\MessageBox.py', '','',1)# 运行MessageBox.py脚本
def test2():
# 打开记事本程序,在后台运行,即显示记事本程序的窗口
win32api.ShellExecute(0, 'open', 'notepad.exe',
r'C:\ProgramData\MySQL\MySQL Server 8.0\my.ini','',1)
win32api.ShellExecute(0, 'open', 'notepad.exe', 'my.ini',
'C:\\ProgramData\\MySQL\\MySQL Server 8.0\\', 1)
win32api.ShellExecute(0, 'open', 'goldminer3.exe', '--username=131628911xx -- password=xx',
'C:\\Users\\Administrator\\AppData\\Roaming\\Goldminer3\\', 1)
test2()
3 CreateProcess(appName, commandLine , processAttributes , threadAttributes ,
bInheritHandles ,dwCreationFlags , newEnvironment , currentDirectory , startupinfo ):
import win32process,win32event
handle = win32process.CreateProcess('c:\\windows\\notepad.exe', '',None , None , 0 ,
win32process. CREATE_NO_WINDOW , None , None ,win32process.STARTUPINFO())
# 打开记事本获得其句柄
#(<?XML:NAMESPACE PREFIX = PYHANDLE />, , 280, 3076)
# 函数返回进程句柄、线程句柄、进程ID,以及线程ID
win32process.TerminateProcess(handle[0],0) #用TerminateProcess函数终止记事本程序
win32event.WaitForSingleObject(handle[0], -1)# 等待进程结束0进程结束的返回值
4 使用ctypes调用kernel32.dll中的函数:
import win32process,win32event
handle = win32process.CreateProcess('c:\\windows\\notepad.exe', '',None , None , 0 ,
win32process. CREATE_NO_WINDOW , None , None ,win32process.STARTUPINFO())
# 打开记事本获得其句柄
#(<?XML:NAMESPACE PREFIX = PYHANDLE />, , 280, 3076)
# 函数返回进程句柄、线程句柄、进程ID,以及线程ID
win32process.TerminateProcess(handle[0],0) #用TerminateProcess函数终止记事本程序
win32event.WaitForSingleObject(handle[0], -1)# 等待进程结束0进程结束的返回值
from ctypes import *
user32 = windll.LoadLibrary('user32.dll') # 加载动态链接库
user32.MessageBoxA(0, 'Ctypes is cool!', 'Ctypes', 0)# 调用MessageBoxA函数
.
5.os.popen运行dos命令:
print(os.popen('dir').read())
6.subprocess:
import sys,os,subprocess
from subprocess import Popen,PIPE
def test2():# 用subprocess.Popen执行.exe程序
order_name="goldminer3.exe --username=13162891176 --password=tcy-1974"
path='C:\\Users\\Administrator\\AppData\\Roaming\\Goldminer3\\'
#cwd指定子进程工作路径
p=subprocess.Popen(order_name,shell=True,stdout=subprocess.PIPE,cwd=path)#程序阻塞
s=p.stdout.read()#b"\r\n[main \xe4\xb8\x8b\xe5\x8d\x885:20:25]..."
s=s.split()
lst=[i.decode() for i in s]
print(lst) #['[main', '下午5:23:17]', 'update#setState', 'idle', ...]
# test2()
实例:
def test3(): # 用subprocess.Popen执行系统命令
p= Popen('cd', shell=True,stdout=subprocess.PIPE)#windows执行cd命令获取当前目录
print('p=',p.stdout.read()) #b'D:\\PycharmProjects\\test_py36\r\n'
print(os.popen('cd').read()) # C:\Users\Administrator\AppData\Roaming\Goldminer3
p = Popen('python c:\b.py', shell=True, stdout=PIPE) # 运行脚本b.py
p.wait() # 获取Popen的返回值及输出
if (p.returncode == 0): print("当前目录:%s" % p2.stdout.read())
#test3()
win32gui
官网:http://timgolden.me.uk/pywin32-docs/win32gui.html
实例1:
import win32gui,win32con,win32api
import time
def test_win32gui():
hwnd = win32gui.FindWindow("TXGuiFoundation", "TIM")#找主窗口
print('hwnd=%0x'%hwnd,hwnd)#hwnd=a0b42 658242
Ex_hwnd=win32gui.FindWindowEx(hwnd,None,'Edit',None)
print('Ex_hwnd=%0x'%Ex_hwnd)#Ex_hwnd=a0af8
# hhwndChildList = [] # 枚举子窗口
# win32gui.EnumChildWindows(hwnd, lambda hhwnd, param: param.append(hhwnd),
hhwndChildList)
# print('hhwndChildList= ',hhwndChildList) #[789286]
time.sleep(2)
win32gui.CloseWindow(hwnd)
#窗口最小化
time.sleep(2)
win32gui.SendMessage(hwnd, win32con.WM_CLOSE) #关闭窗口
test_win32gui()
win32gui.方法:
FindWindow(lpClassName=None, lpWindowName=None) 窗口类名 窗口标题名
方法:
FindWindowEx(hhwndParent=0, hhwndChildAfter=0, lpszClass=None, lpszWindow=None);
描述:搜索类名和窗体名匹配的窗体,并返回这个窗体的句柄。不区分大小写,找不到就返回0。
参数:
hhwndParent: 若不为0,则搜索句柄为hhwndParent窗体的子窗体。
hhwndChildAfter:若不为0,则按照z-index的顺序从hhwndChildAfter向后开始搜索子窗体,
否则从第一个子窗体开始搜索。
lpClassName: 字符型,是窗体的类名,这个可以在Spy++里找到。
lpWindowName:字符型,是窗口名,也就是标题栏上你能看见的那个标题。
说明:找到了主窗口以后就靠它来定位子窗体啦。
方法:
left,top,right,bottom=win32gui.GetWindowRect(hnd)# 获取窗口位置-屏幕坐标中窗口的矩形
win32gui.SetWindowPos(hwnd,win32con.HWND_TOPMOST,x,y,400,400,win32con.SWP_SHOWWINDOW)
title = win32gui.GetWindowText(hnd) #获取某个句柄的标题
clsname = win32gui.GetClassName(hnd)#获取某个句柄的类名
GetClientRect #在客户端坐标中返回窗口客户区的矩形
SetWindowPos #设置窗口的位置和大小
SetWindowPlacement#设置窗口位置的RegisterClass
ScreenToClient #将屏幕坐标转换为客户端坐标
ClientToScreen #将客户端坐标转换为屏幕坐标
HCURSOR = win32gui.GetCursor()
win32api.SetCursorPos([30,50]) # 鼠标定位到(30,50)
ctrlid=win32gui.GetDlgCtrlID(hwnd) #控件的窗口id
ctrl2=win32gui.GetDlgItem(hwnd,ctrlid)#控件句柄
buffer = '0' *50
len = win32gui.SendMessage(hwnd, win32con.WM_GETTEXTLENGTH)+1 #获取edit控件文本长度
win32gui.SendMessage(hwnd, win32con.WM_GETTEXT, len, buffer) #读取文本
print('buffer=',len,buffer)
方法:
menuHandle = win32gui.GetMenu(subHandle)# 获得窗口的菜单句柄
# 获得子菜单或下拉菜单句柄
subMenuHandle = win32gui.GetSubMenu(menuHandle, 0)# 参数:菜单句柄 子菜单索引号
# 获得菜单项中的的标志符,注意,分隔符是被编入索引的
menuItemHandle = win32gui.GetMenuItemID(subMenuHandle, 0)# 参数:子菜单句柄 项目索引号
方法:
# 发送消息,加入消息队列,无返回
win32gui.postMessage(subHandle,win32con.WM_COMMAND, menuItemHandle, 0)
参数:句柄 消息类型 WParam IParam
wParam的定义是32位整型,high word就是他的31至16位,low word是它的15至0位。
当参数超过两个,wParam和lParam不够用时,可以将wParam就给拆成两个int16来使用。
把HIWORD的常数向左移16位,再加LOWORD,即wParam = HIWORD<<16+LOWORD。
方法:
下选框内容更改
参数:下选框句柄; 消息内容; 参数下选框的哪一个item,以0起始的待选选项的索引;
如果该值为-1,将从组合框列表中删除当前选项,并使当前选项为空;
参数CB_Handle为下选框句柄,PCB_hnd下选框父窗口句柄
win32api.SendMessage(CB_hnd, win32con.CB_SETCURSEL, 1, 0)
方法:
下选框的父窗口命令
参数:父窗口句柄; 命令; 参数:WParam:高位表示类型,低位表示内容;参数IParam,
下选框句柄CBN_SELENDOK当用户选择了有效的列表项时发送,提示父窗体处理用户的选择。
LOWORD为组合框的ID. HIWORD为CBN_SELENDOK的值。
win32api.SendMessage(PCB_hnd, win32con.WM_COMMAND, 0x90000, CB_hnd)
方法:
CBN_SELCHANGE当用户更改了列表项的选择时发送,
不论用户是通过鼠标选择或是通过方向键选择都会发送此通知。
LOWORD为组合框的ID. HIWORD为CBN_SELCHANGE的值。
win32api.SendMessage(PCB_hnd, win32con.WM_COMMAND, 0x10000, CB_hnd)
方法:
# 设置文本框内容,等窗口处理完毕后返回true。中文需编码成gbk
# 参数:句柄;消息类型;参数WParam,无需使用; 参数IParam,要设置的内容,字符串
win32api.SendMessage(hnd,win32con.WM_SETTEXT,0,os.path.abspath(fgFilePath).encode('gbk'))
# 控件点击确定,处理消息后返回0
# 参数:窗口句柄; 消息类型; 参数WParam HIWORD为0(未使用),LOWORD为控件的ID;
参数IParam 0(未使用),确定控件的句柄
win32api.SendMessage(Mhnd, win32con.WM_COMMAND, 1, confirmBTN_hnd)
# 获取窗口文本不含截尾空字符的长度
# 参数:窗口句柄; 消息类型; 参数WParam; 参数IParam
bufSize = win32api.SendMessage(subHandle, win32con.WM_GETTEXTLENGTH, 0, 0) +1
# 利用api生成Buffer
strBuf = win32gui.PyMakeBuffer(bufSize)
print(strBuf)
# 发送消息获取文本内容
# 参数:窗口句柄; 消息类型;文本大小; 存储位置
length = win32gui.SendMessage(subHandle, win32con.WM_GETTEXT, bufSize, strBuf)
text = str(strBuf[:-1])# 反向内容,转为字符串
address, length = win32gui.PyGetBufferAddressAndLen(strBuf)
text = win32gui.PyGetString(address, length)
win32api.MessageBox(hnd,text,text)
print('text: ', text)
2.鼠标单击事件:
win32api.SetCursorPos([30,50])#鼠标定位到(30,50)
#执行左单键击,若需要双击则延时几毫秒再点击一次即可
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP | win32con.MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0)
#右键单击
win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP | win32con.MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0)
实例:
def click1(x,y): #第一种
win32api.SetCursorPos((x,y))
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,x,y,0,0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,x,y,0,0)
def click2(x,y): #第二种
ctypes.windll.user32.SetCursorPos(x,y)
ctypes.windll.user32.mouse_event(2,0,0,0,0)
ctypes.windll.user32.mouse_event(4,0,0,0,0)
def click_it(pos): #第三种
hnd= win32gui.WindowFromPoint(pos)
client_pos =win32gui.ScreenToClient(hnd,pos)
tmp=win32api.MAKELONG(client_pos[0],client_pos[1])
win32gui.SendMessage(hnd, win32con.WM_ACTIVATE,win32con.WA_ACTIVE,0)
win32gui.SendMessage(hnd, win32con.WM_LBUTTONDOWN,win32con.MK_LBUTTON,tmp)
win32gui.SendMessage(hnd, win32con.WM_LBUTTONUP,win32con.MK_LBUTTON,tmp)
实例:
# 发送回车
win32api.keybd_event(13,0,0,0)
win32api.keybd_event(13,0,win32con.KEYEVENTF_KEYUP,0)
实例:
# 关闭窗口
win32gui.PostMessage(win32lib.findWindow(classname, titlename), win32con.WM_CLOSE, 0, 0)
# 检查窗口是否最小化,如果是最大化
if(win32gui.IsIconic(hhwnd)):
# win32gui.ShowWindow(hhwnd, win32con.SW_SHOWNORMAL)
win32gui.ShowWindow(hhwnd, 8)
sleep(0.5)
说明:
参数 | 说明 |
SW_HIDE | 隐藏窗口并激活其他窗口。nCmdShow=0。 |
SW_MAXIMIZE | 最大化指定的窗口。nCmdShow=3。 |
SW_MINIMIZE | 最小化指定的窗口并且激活在Z序中的下一个顶层窗口。nCmdShow=6。 |
SW_RESTORE | 激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。 |
| 在恢复最小化窗口时,应用程序应该指定这个标志。nCmdShow=9。 |
SW_SHOW | 在窗口原来的位置以原来的尺寸激活和显示窗口。nCmdShow=5。 |
SW_SHOWDEFAULT | 依据在STARTUPINFO结构中指定的SW_FLAG标志设定显示状态, |
| STARTUPINFO 结构是由启动应用程序的程序传递给CreateProcess。nCmdShow=10。 |
SW_SHOWMAXIMIZED | 激活窗口并将其最大化。nCmdShow=3。 |
SW_SHOWMINIMIZED | 激活窗口并将其最小化。nCmdShow=2。 |
SW_SHOWMINNOACTIVE | 窗口最小化,激活窗口仍然维持激活状态。nCmdShow=7。 |
SW_SHOWNA | 以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=8。 |
SW_SHOWNOACTIVATE | 以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=4。 |
SW_SHOWNORMAL | 激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。 |
| 应用程序在第一次显示窗口的时候应该指定此标志。nCmdShow=1。 |
实例:
# win32虽然也可控制键盘,但不如使用PyUserInput的方便
from pymouse import PyMouse
from pykeyboard import PyKeyboard
m = PyMouse()
k = PyKeyboard()
x_dim, y_dim = m.screen_size()
# 鼠标点击
m.click(x_dim/2, y_dim/2, 1)
# 键盘输入
k.type_string('Hello, World!')
# 按住一个键
k.press_key('H')
# 松开一个键
k.release_key('H')
# 按住并松开,tap一个键
k.tap_key('e')
# tap支持重复的间歇点击键
k.tap_key('l',n=2,interval=5)
# 发送判断文字
k.type_string('123456')
#创建组合键
k.press_key(k.alt_key)
k.tap_key(k.tab_key)
k.release_key(k.alt_key)
# 特殊功能键
k.tap_key(k.function_keys[5]) # Tap F5
k.tap_key(k.numpad_keys['Home']) # Tap 'Home' on the numpad
k.tap_key(k.numpad_keys[5], n=3) # Tap 5 on the numpad, thrice
# Mac系统
k.press_keys(['Command','shift','3'])
# Windows系统
k.press_keys([k.windows_l_key,'d'])
# 其中的PyMouseEvent和PyKeyboardEvent还可用于监听鼠标和键盘事件的输入