中文官方文档
pywinauto是一组用于自动化Microsoft Windows GUI的python模块。 最简单的是,它允许您将鼠标和键盘操作发送到窗口对话框和控件。
pip install pywinauto
代码如下(示例):
self.app_path = "D:/package/DingDing/main/current/DingTalk.exe"
app = Application(backend="uia").start(self.app_path)
官方文档
PyQt5 是Digia的一套Qt5应用框架与python的结合,同时支持2.x和3.x。本教程使用的是3.x。Qt库由Riverbank Computing开发,是最强大的GUI库之一。
pip install PyQt5
pip install pyqt5-tools
参考如何配置
代码如下(示例):
1.设计界面
在PyCharm中创建一个项目,然后点击“Tools”–“External Tools”–“QTDesinger”打开QT Desinger
2. 设计如下
保存,生成如下UI代码。
ui_mainwindow.ui
MainWindow
0
0
807
676
Check Account
false
-
Arial
10
2
16
16
Arial
10
50
false
Tool
340
170
71
31
RunButton
70
20
641
131
Times New Roman
9
50
false
70
220
641
341
Times New Roman
9
50
false
10
10
51
51
Arial
9
50
false
Account
10
220
41
31
Arial
9
50
false
Logs
false
. .
Multiple
10
20
51
31
Arial
9
Excel
510
20
75
31
Arial
10
Select
10
120
51
51
Arial
9
Account
10
330
41
31
Arial
9
Logs
360
280
81
31
Arial
10
RunButton
70
130
641
131
Times New Roman
9
70
330
641
231
Times New Roman
9
10
70
51
31
Arial
9
Zoom
510
70
75
31
Arial
10
Select
70
19
411
31
Times New Roman
9
70
70
411
31
Times New Roman
9
label
label_2
label_3
pushButton_2
pushButton
textEdit_6
textEdit_8
label_14
pushButton_5
lineEdit
lineEdit_2
Single
10
70
61
31
Arial
9
Username
10
120
61
31
Arial
9
Password
10
171
121
31
Arial
9
Buy A License
10
220
91
31
Arial
9
AccountType
400
70
54
31
Arial
9
Role
400
110
71
51
Arial
9
UserType
400
160
54
51
Arial
9
K12(Y/N)
600
271
91
31
Arial
10
RunButton
270
171
81
31
Arial
10
No
150
171
71
31
Arial
10
Yes
true
false
100
221
231
31
Times New Roman
10
ArrowCursor
-
-
enterprise-activehost
-
Education
-
biz-enterprise
-
Single Pro (Named Host)
-
single pro+webinar
-
free with cc
-
free without cc
-
freetrail
-
ZR
-
pro(license>1)
-
biz(license<100)
-
API
-
free with CC (Free-type2)
-
free with CC (EDU - K12)
480
120
211
31
Times New Roman
10
-
-
License
-
Basic
-
On-Prem
10
330
54
31
Arial
9
Logs
100
330
591
211
Times New Roman
10
480
70
211
31
Times New Roman
10
-
-
owner
-
member
480
170
211
31
Times New Roman
10
-
-
Yes
-
No
10
20
71
31
Arial
9
Zoom Path
600
20
91
31
Arial
10
Select
100
20
381
31
Times New Roman
10
100
70
271
31
Times New Roman
10
100
120
271
31
Times New Roman
10
0
0
807
23
转换为python代码
ui_mainwindow.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_mainwindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(807, 676)
MainWindow.setStyleSheet("")
MainWindow.setUnifiedTitleAndToolBarOnMac(False)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setStyleSheet("")
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.tabWidget.setFont(font)
self.tabWidget.setStyleSheet("")
self.tabWidget.setIconSize(QtCore.QSize(16, 16))
self.tabWidget.setObjectName("tabWidget")
self.tab_3 = QtWidgets.QWidget()
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
font.setWeight(50)
self.tab_3.setFont(font)
self.tab_3.setObjectName("tab_3")
self.pushButton_6 = QtWidgets.QPushButton(self.tab_3)
self.pushButton_6.setGeometry(QtCore.QRect(340, 170, 71, 31))
self.pushButton_6.setObjectName("pushButton_6")
self.textEdit_11 = QtWidgets.QTextEdit(self.tab_3)
self.textEdit_11.setGeometry(QtCore.QRect(70, 20, 641, 131))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(9)
font.setBold(False)
font.setWeight(50)
self.textEdit_11.setFont(font)
self.textEdit_11.setObjectName("textEdit_11")
self.textEdit_12 = QtWidgets.QTextEdit(self.tab_3)
self.textEdit_12.setGeometry(QtCore.QRect(70, 220, 641, 341))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(9)
font.setBold(False)
font.setWeight(50)
self.textEdit_12.setFont(font)
self.textEdit_12.setObjectName("textEdit_12")
self.label_15 = QtWidgets.QLabel(self.tab_3)
self.label_15.setGeometry(QtCore.QRect(10, 10, 51, 51))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
font.setBold(False)
font.setWeight(50)
self.label_15.setFont(font)
self.label_15.setObjectName("label_15")
self.label_16 = QtWidgets.QLabel(self.tab_3)
self.label_16.setGeometry(QtCore.QRect(10, 220, 41, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
font.setBold(False)
font.setWeight(50)
self.label_16.setFont(font)
self.label_16.setObjectName("label_16")
self.tabWidget.addTab(self.tab_3, "")
self.tab = QtWidgets.QWidget()
self.tab.setTabletTracking(False)
self.tab.setObjectName("tab")
self.label = QtWidgets.QLabel(self.tab)
self.label.setGeometry(QtCore.QRect(10, 20, 51, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label.setFont(font)
self.label.setObjectName("label")
self.pushButton = QtWidgets.QPushButton(self.tab)
self.pushButton.setGeometry(QtCore.QRect(510, 20, 75, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.pushButton.setFont(font)
self.pushButton.setObjectName("pushButton")
self.label_2 = QtWidgets.QLabel(self.tab)
self.label_2.setGeometry(QtCore.QRect(10, 120, 51, 51))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_2.setFont(font)
self.label_2.setObjectName("label_2")
self.label_3 = QtWidgets.QLabel(self.tab)
self.label_3.setGeometry(QtCore.QRect(10, 330, 41, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_3.setFont(font)
self.label_3.setObjectName("label_3")
self.pushButton_2 = QtWidgets.QPushButton(self.tab)
self.pushButton_2.setGeometry(QtCore.QRect(360, 280, 81, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.pushButton_2.setFont(font)
self.pushButton_2.setObjectName("pushButton_2")
self.textEdit_6 = QtWidgets.QTextEdit(self.tab)
self.textEdit_6.setGeometry(QtCore.QRect(70, 130, 641, 131))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(9)
self.textEdit_6.setFont(font)
self.textEdit_6.setObjectName("textEdit_6")
self.textEdit_8 = QtWidgets.QTextEdit(self.tab)
self.textEdit_8.setGeometry(QtCore.QRect(70, 330, 641, 231))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(9)
self.textEdit_8.setFont(font)
self.textEdit_8.setObjectName("textEdit_8")
self.label_14 = QtWidgets.QLabel(self.tab)
self.label_14.setGeometry(QtCore.QRect(10, 70, 51, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_14.setFont(font)
self.label_14.setObjectName("label_14")
self.pushButton_5 = QtWidgets.QPushButton(self.tab)
self.pushButton_5.setGeometry(QtCore.QRect(510, 70, 75, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.pushButton_5.setFont(font)
self.pushButton_5.setObjectName("pushButton_5")
self.lineEdit = QtWidgets.QLineEdit(self.tab)
self.lineEdit.setGeometry(QtCore.QRect(70, 19, 411, 31))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(9)
self.lineEdit.setFont(font)
self.lineEdit.setObjectName("lineEdit")
self.lineEdit_2 = QtWidgets.QLineEdit(self.tab)
self.lineEdit_2.setGeometry(QtCore.QRect(70, 70, 411, 31))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(9)
self.lineEdit_2.setFont(font)
self.lineEdit_2.setObjectName("lineEdit_2")
self.label.raise_()
self.label_2.raise_()
self.label_3.raise_()
self.pushButton_2.raise_()
self.pushButton.raise_()
self.textEdit_6.raise_()
self.textEdit_8.raise_()
self.label_14.raise_()
self.pushButton_5.raise_()
self.lineEdit.raise_()
self.lineEdit_2.raise_()
icon = QtGui.QIcon.fromTheme("dsa")
self.tabWidget.addTab(self.tab, icon, "")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.label_4 = QtWidgets.QLabel(self.tab_2)
self.label_4.setGeometry(QtCore.QRect(10, 70, 61, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_4.setFont(font)
self.label_4.setObjectName("label_4")
self.label_5 = QtWidgets.QLabel(self.tab_2)
self.label_5.setGeometry(QtCore.QRect(10, 120, 61, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
self.label_6 = QtWidgets.QLabel(self.tab_2)
self.label_6.setGeometry(QtCore.QRect(10, 171, 121, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_6.setFont(font)
self.label_6.setObjectName("label_6")
self.label_7 = QtWidgets.QLabel(self.tab_2)
self.label_7.setGeometry(QtCore.QRect(10, 220, 91, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_7.setFont(font)
self.label_7.setObjectName("label_7")
self.label_8 = QtWidgets.QLabel(self.tab_2)
self.label_8.setGeometry(QtCore.QRect(400, 70, 54, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_8.setFont(font)
self.label_8.setObjectName("label_8")
self.label_9 = QtWidgets.QLabel(self.tab_2)
self.label_9.setGeometry(QtCore.QRect(400, 110, 71, 51))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_9.setFont(font)
self.label_9.setObjectName("label_9")
self.label_10 = QtWidgets.QLabel(self.tab_2)
self.label_10.setGeometry(QtCore.QRect(400, 160, 54, 51))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_10.setFont(font)
self.label_10.setObjectName("label_10")
self.pushButton_3 = QtWidgets.QPushButton(self.tab_2)
self.pushButton_3.setGeometry(QtCore.QRect(600, 271, 91, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.pushButton_3.setFont(font)
self.pushButton_3.setObjectName("pushButton_3")
self.radioButton = QtWidgets.QRadioButton(self.tab_2)
self.radioButton.setGeometry(QtCore.QRect(270, 171, 81, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.radioButton.setFont(font)
self.radioButton.setObjectName("radioButton")
self.radioButton_2 = QtWidgets.QRadioButton(self.tab_2)
self.radioButton_2.setGeometry(QtCore.QRect(150, 171, 71, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.radioButton_2.setFont(font)
self.radioButton_2.setChecked(True)
self.radioButton_2.setAutoRepeat(False)
self.radioButton_2.setObjectName("radioButton_2")
self.comboBox = QtWidgets.QComboBox(self.tab_2)
self.comboBox.setGeometry(QtCore.QRect(100, 221, 231, 31))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(10)
self.comboBox.setFont(font)
self.comboBox.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor))
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("")
self.comboBox.setItemText(0, "")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox_2 = QtWidgets.QComboBox(self.tab_2)
self.comboBox_2.setGeometry(QtCore.QRect(480, 120, 211, 31))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(10)
self.comboBox_2.setFont(font)
self.comboBox_2.setObjectName("comboBox_2")
self.comboBox_2.addItem("")
self.comboBox_2.setItemText(0, "")
self.comboBox_2.addItem("")
self.comboBox_2.addItem("")
self.comboBox_2.addItem("")
self.label_12 = QtWidgets.QLabel(self.tab_2)
self.label_12.setGeometry(QtCore.QRect(10, 330, 54, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_12.setFont(font)
self.label_12.setObjectName("label_12")
self.textEdit_4 = QtWidgets.QTextEdit(self.tab_2)
self.textEdit_4.setGeometry(QtCore.QRect(100, 330, 591, 211))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(10)
self.textEdit_4.setFont(font)
self.textEdit_4.setStyleSheet("")
self.textEdit_4.setObjectName("textEdit_4")
self.comboBox_3 = QtWidgets.QComboBox(self.tab_2)
self.comboBox_3.setGeometry(QtCore.QRect(480, 70, 211, 31))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(10)
self.comboBox_3.setFont(font)
self.comboBox_3.setObjectName("comboBox_3")
self.comboBox_3.addItem("")
self.comboBox_3.setItemText(0, "")
self.comboBox_3.addItem("")
self.comboBox_3.addItem("")
self.comboBox_4 = QtWidgets.QComboBox(self.tab_2)
self.comboBox_4.setGeometry(QtCore.QRect(480, 170, 211, 31))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(10)
self.comboBox_4.setFont(font)
self.comboBox_4.setObjectName("comboBox_4")
self.comboBox_4.addItem("")
self.comboBox_4.setItemText(0, "")
self.comboBox_4.addItem("")
self.comboBox_4.addItem("")
self.label_13 = QtWidgets.QLabel(self.tab_2)
self.label_13.setGeometry(QtCore.QRect(10, 20, 71, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.label_13.setFont(font)
self.label_13.setObjectName("label_13")
self.pushButton_4 = QtWidgets.QPushButton(self.tab_2)
self.pushButton_4.setGeometry(QtCore.QRect(600, 20, 91, 31))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.pushButton_4.setFont(font)
self.pushButton_4.setObjectName("pushButton_4")
self.lineEdit_3 = QtWidgets.QLineEdit(self.tab_2)
self.lineEdit_3.setGeometry(QtCore.QRect(100, 20, 381, 31))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(10)
self.lineEdit_3.setFont(font)
self.lineEdit_3.setObjectName("lineEdit_3")
self.lineEdit_4 = QtWidgets.QLineEdit(self.tab_2)
self.lineEdit_4.setGeometry(QtCore.QRect(100, 70, 271, 31))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(10)
self.lineEdit_4.setFont(font)
self.lineEdit_4.setObjectName("lineEdit_4")
self.lineEdit_5 = QtWidgets.QLineEdit(self.tab_2)
self.lineEdit_5.setGeometry(QtCore.QRect(100, 120, 271, 31))
font = QtGui.QFont()
font.setFamily("Times New Roman")
font.setPointSize(10)
self.lineEdit_5.setFont(font)
self.lineEdit_5.setObjectName("lineEdit_5")
self.tabWidget.addTab(self.tab_2, "")
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 807, 23))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
self.tabWidget.setCurrentIndex(2)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Check Account"))
self.pushButton_6.setText(_translate("MainWindow", "RunButton"))
self.label_15.setText(_translate("MainWindow", "Account"))
self.label_16.setText(_translate("MainWindow", "Logs"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "Tool"))
self.label.setText(_translate("MainWindow", "Excel"))
self.pushButton.setText(_translate("MainWindow", "Select"))
self.label_2.setText(_translate("MainWindow", "Account"))
self.label_3.setText(_translate("MainWindow", "Logs"))
self.pushButton_2.setText(_translate("MainWindow", "RunButton"))
self.label_14.setText(_translate("MainWindow", "Zoom"))
self.pushButton_5.setText(_translate("MainWindow", "Select"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Multiple"))
self.label_4.setText(_translate("MainWindow", "Username"))
self.label_5.setText(_translate("MainWindow", "Password"))
self.label_6.setText(_translate("MainWindow", "Buy A License"))
self.label_7.setText(_translate("MainWindow", "AccountType"))
self.label_8.setText(_translate("MainWindow", "Role"))
self.label_9.setText(_translate("MainWindow", "UserType"))
self.label_10.setText(_translate("MainWindow", "K12(Y/N)"))
self.pushButton_3.setText(_translate("MainWindow", "RunButton"))
self.radioButton.setText(_translate("MainWindow", "No"))
self.radioButton_2.setText(_translate("MainWindow", "Yes"))
self.comboBox.setItemText(1, _translate("MainWindow", "Enterprise-activehost"))
self.comboBox.setItemText(2, _translate("MainWindow", "Education"))
self.comboBox.setItemText(3, _translate("MainWindow", "Biz-enterprise"))
self.comboBox.setItemText(4, _translate("MainWindow", "Single Pro (Named Host)"))
self.comboBox.setItemText(5, _translate("MainWindow", "Single Pro+webinar"))
self.comboBox.setItemText(6, _translate("MainWindow", "Free with cc"))
self.comboBox.setItemText(7, _translate("MainWindow", "Free without cc"))
self.comboBox.setItemText(8, _translate("MainWindow", "Freetrail"))
self.comboBox.setItemText(9, _translate("MainWindow", "ZR"))
self.comboBox.setItemText(10, _translate("MainWindow", "Pro(license>1)"))
self.comboBox.setItemText(11, _translate("MainWindow", "Biz(license<100)"))
self.comboBox.setItemText(12, _translate("MainWindow", "API"))
self.comboBox.setItemText(13, _translate("MainWindow", "Free with CC (Free-type2)"))
self.comboBox.setItemText(14, _translate("MainWindow", "Free with CC (EDU-K12)"))
self.comboBox_2.setItemText(1, _translate("MainWindow", "License"))
self.comboBox_2.setItemText(2, _translate("MainWindow", "Basic"))
self.comboBox_2.setItemText(3, _translate("MainWindow", "On-Prem"))
self.label_12.setText(_translate("MainWindow", "Logs"))
self.comboBox_3.setItemText(1, _translate("MainWindow", "Owner"))
self.comboBox_3.setItemText(2, _translate("MainWindow", "Member"))
self.comboBox_4.setItemText(1, _translate("MainWindow", "Yes"))
self.comboBox_4.setItemText(2, _translate("MainWindow", "No"))
self.label_13.setText(_translate("MainWindow", "Zoom Path"))
self.pushButton_4.setText(_translate("MainWindow", "Select"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Single"))
# -*- coding: utf-8 -*-
import os
import sys
import time
import threading
from mainwindow import MainWindow
from PyQt5.QtWidgets import QApplication
parent_path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(parent_path)
class RunGUI(object):
"""运行GUI界面"""
def gui_start(self):
"""启动gui界面"""
app = QApplication(sys.argv) # QApplication采用事件循环机制,当QApplication初始化后,就进入应用程序的主循环
main_window = MainWindow() # 打开主界面
main_window.show() # 显示主界面
sys.exit(app.exec_()) # sys.exit()函数可以结束一个应用程序,使应用程序在主循环中退出。
def create_thread(self, func, *args):
"""将函数放入线程中执行"""
t = threading.Thread(target=func, args=args) # 创建线程
t.setDaemon(True) # 守护线程
t.start() # 启动线程
def run(self):
self.create_thread(self.gui_start) # 将GUI界面放到守护线程中运行
while True:
time.sleep(1)
print(len(threading.enumerate()))
if len(threading.enumerate()) < 2: # 当只剩下1个线程时,即GUI线程关闭,主线程退出
break
if __name__ == '__main__':
r = RunGUI()
r.run()
mainwindow.py
# coding: utf-8
import os
import xlrd
from PyQt5 import QtWidgets
from PyQt5.QtGui import QTextCursor
from thread_work import WorkThread
from ui_mainwindow import Ui_MainWindow
from PyQt5.QtWidgets import QMessageBox, QWidget, QMainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
"""GUI主界面操作"""
def __init__(self):
"""初始化"""
super(MainWindow, self).__init__() # super().__init__()继承父类的init方法
self.setupUi(self) # 初始化窗口
self.app_path = None # app路径
self.account_lists = [] # 账号list
self.account_path = None # 账号路径
self.thread = None # 初始化线程
self.log_msg = "" # 简单界面log日志
# 绑定多账号按钮点击事件
self.pushButton.clicked.connect(self.get_multiple_file_path) # 绑定账号文件选择按钮点击事件
self.pushButton_5.clicked.connect(self.get_multiple_app_path) # 绑定app选择按钮点击事件
self.pushButton_2.clicked.connect(self.multiple_run_button) # 绑定运行按钮点击事件
# 绑定单账号按钮点击事件
self.pushButton_3.clicked.connect(self.single_run_button) # 绑定运行按钮点击事件
self.pushButton_4.clicked.connect(self.get_single_app_path) # 绑定app选择按钮点击事件
# 绑定多账号简单界面按钮点击事件
self.pushButton_6.clicked.connect(self.simple_run_button) # 绑定app选择按钮点击事件
def simple_run_button(self):
"""多账号简单界面点击运行按钮"""
self.pushButton_6.setEnabled(False)
app_path = os.getenv("APPDATA") + "\\Zoom\\bin\\Zoom.exe" # 获取app路径
self.account_path = os.getcwd() + "\\Zoom.xlsx" # 获取账号文件路径
self.get_account()
self.thread = WorkThread() # 初始化一条线程
self.thread.account_lists = self.account_lists # 将账号list传给线程
self.thread.app_path = app_path # 将 app path 传给线程
if app_path:
self.thread.sinOut.connect(self.simple_output) # 绑定信号槽,获取信号
self.thread.complete_sinOut.connect(self.simple_complete_sinOut)
self.thread.start() # 开启线程
else:
w = QWidget()
QMessageBox.about(w, 'Error', 'Failed to get Zoom.exe path')
self.pushButton_6.setEnabled(True)
def simple_complete_sinOut(self, msg):
"""多账号简单界面完成信号槽信息"""
w = QWidget()
QMessageBox.about(w, 'Success', 'All account test completed')
self.pushButton_6.setEnabled(True)
def simple_output(self, msg):
"""多账号简单界面信号槽信息"""
res = self.account_msg(msg[0]) # 拼接账号信息显示框展示内容
self.textEdit_11.setText(res)
log = self.logs_msg(msg[1]) # 拼接账号信息显示框展示内容
self.log_msg += log
self.textEdit_12.setText(self.log_msg)
self.move_cursor(self.textEdit_12) # 移动光标到文档最后
self.pushButton_6.setEnabled(False)
def get_multiple_file_path(self):
"""多账号界面获取账号文件信息"""
account_path, file_type = QtWidgets.QFileDialog.getOpenFileName(None, "选取账号文件",
os.getcwd() + "\\Zoom.xlsx", ) # 打开文件选择框
if str(account_path).strip() == "" or str(account_path).split(".")[-1] != "xlsx":
w = QWidget()
QMessageBox.about(w, 'Error', 'The file is not xlsx') # 提示框
self.account_path = ''
self.lineEdit.setText(self.account_path) # 设置输入框value
else:
self.account_path = account_path
self.lineEdit.setText(self.account_path)
def get_multiple_app_path(self):
"""多账号界面获取app路径"""
if self.account_path:
self.get_account() # 调用读取账号文件函数获取所有账号list
app_path, file_type = QtWidgets.QFileDialog.getOpenFileName(None, "选取Zoom软件", os.getenv(
"APPDATA") + "\\Zoom\\bin\\Zoom.exe", ) # 路径
if str(app_path).strip() == "" or app_path.split("/")[-1] != "Zoom.exe":
w = QWidget()
QMessageBox.about(w, 'Error', 'The file is not Zoom.exe')
self.app_path = ''
self.lineEdit_2.setText(self.app_path)
else:
self.lineEdit_2.setText(app_path)
self.app_path = app_path
else:
w = QWidget()
QMessageBox.about(w, 'Error', 'Please select the account path')
self.pushButton_2.setEnabled(True) # 设置按钮可点击状态
def multiple_run_button(self):
"""多账号界面点击运行按钮"""
self.pushButton_2.setEnabled(False)
self.thread = WorkThread() # 初始化一条线程
self.thread.account_lists = self.account_lists # 将账号list传给线程
self.thread.app_path = self.app_path # 将 app path 传给线程
if self.app_path:
self.thread.sinOut.connect(self.multiple_output) # 绑定信号槽,获取信号
self.thread.complete_sinOut.connect(self.multiple_complete_sinOut)
self.thread.start() # 开启线程
else:
w = QWidget()
QMessageBox.about(w, 'Error', 'Please select the Zoom.exe path')
self.pushButton_2.setEnabled(True)
def multiple_complete_sinOut(self, msg):
"""多账号界面完成信号槽信息"""
w = QWidget()
QMessageBox.about(w, 'Success', 'All account test completed')
self.pushButton_2.setEnabled(True)
def multiple_output(self, msg):
"""多账号界面信号槽信息"""
res = self.account_msg(msg[0]) # 拼接账号信息显示框展示内容
self.textEdit_6.setText(res)
log = self.logs_msg(msg[1]) # 拼接账号信息显示框展示内容
self.log_msg += log
self.textEdit_8.setText(self.log_msg)
self.move_cursor(self.textEdit_8) # 移动光标到文档最后
self.pushButton_2.setEnabled(False)
def get_single_app_path(self):
"""单账号界面获取app路径"""
app_path, file_type = QtWidgets.QFileDialog.getOpenFileName(None, "选取Zoom软件",
os.getenv("APPDATA") + "\\Zoom\\bin\\Zoom.exe", )
if str(app_path).strip() == "" or app_path.split("/")[-1] != "Zoom.exe":
w = QWidget()
QMessageBox.about(w, 'Error', 'The file is not Zoom.exe')
self.app_path = ''
self.lineEdit_3.setText(self.app_path)
else:
self.lineEdit_3.setText(app_path)
self.app_path = app_path
def single_run_button(self):
"""单账号界面点击运行按钮"""
if self.app_path:
self.pushButton_3.setEnabled(False)
account_dict = {}
username = self.lineEdit_4.text().replace(' ', '') # 获取输入框信息
password = self.lineEdit_5.text().replace(' ', '')
buy_a_license_yes = self.radioButton_2.isChecked() # 获取单选框是否被选择
account_type = self.comboBox.currentText() # 获取复选框当前选择信息
user_type = self.comboBox_2.currentText()
role = self.comboBox_3.currentText()
k12 = self.comboBox_4.currentText()
if buy_a_license_yes:
buy_a_license = "Yes"
else:
buy_a_license = "No"
if self.check_value(username, "Username") and self.check_value(password, "Password") and self.check_value(
account_type, "AccountType") and self.check_value(user_type, "UserType") and \
self.check_value(role, "Role") and self.check_value(k12, "K12"): # 判断所有信息是否都填写完毕
account_dict["AccountType"] = account_type
account_dict["Role"] = role
account_dict["UserType"] = user_type
account_dict["K12"] = k12
account_dict["UserName"] = username
account_dict["PassWord"] = password
account_dict["BuySign"] = buy_a_license
self.account_lists.append(account_dict)
self.thread = WorkThread()
self.thread.account_lists = self.account_lists
self.thread.app_path = self.app_path
self.thread.sinOut.connect(self.single_output)
self.thread.start()
else:
w = QWidget()
QMessageBox.about(w, 'Error', 'Please select the Zoom.exe path')
self.pushButton_3.setEnabled(True)
def single_output(self, msg):
"""单账号界面信号槽信息"""
log = self.logs_msg(msg[1]) # 拼接账号信息显示框展示内容
self.log_msg += log
self.textEdit_4.setText(self.log_msg)
self.pushButton_3.setEnabled(True)
def check_value(self, msg, name):
"""校验单账号界面,输入框、单选框、多选框等信息是否填写"""
if msg.strip() == "":
w = QWidget()
QMessageBox.about(w, 'Error', 'Please input the %s' % name)
self.pushButton_3.setEnabled(True)
return False
else:
return True
def get_account(self):
"""获取账号信息"""
try:
wb = xlrd.open_workbook(self.account_path) # 打开excel文件
table = wb.sheets()[0] # 获取第一个sheet
rows = table.nrows # 总行数
for i in range(1, rows):
account_dict = {}
row_values = table.row_values(i)
account_type = row_values[0]
role = row_values[1]
user_type = row_values[2]
k12 = row_values[3]
username = row_values[4]
password = row_values[5]
buy_sign = row_values[6]
account_dict["UserName"] = str(username).replace(' ', '')
account_dict["PassWord"] = str(password).replace(' ', '')
account_dict["BuySign"] = str(buy_sign).strip()
account_dict["AccountType"] = str(account_type).strip()
account_dict["Role"] = str(role).strip()
account_dict["UserType"] = str(user_type).strip()
account_dict["K12"] = str(k12).strip()
self.account_lists.append(account_dict)
return True
except Exception as e:
w = QWidget() # 没有父类的widget将被作为窗口使用
QMessageBox.about(w, 'Error', 'Failed to read account information in excel!')
return False
def account_msg(self, msg):
"""拼接账号信息显示框展示内容"""
res = ""
for k, v in msg.items():
res += "" + str(
k) + ":" + "" + \
"" + str(v) + "" + "
"
return res
def logs_msg(self, m):
"""装饰日志框展示内容"""
if str(m).__contains__("Fail") or str(m).__contains__("Error"):
msg = "" + str(m) + "" + "
"
else:
msg = "" + str(m) + "" + "
"
return msg
def move_cursor(self, edit):
"""移动光标到文档最后"""
edit.setText(self.log_msg)
cursor = edit.textCursor() # 获取logs框鼠标光标
cursor.movePosition(QTextCursor.End) # 光标移动到文档末尾
edit.setTextCursor(cursor) # 设置文档光标
thread_work.py
# -*- coding: utf-8 -*-
import time
from PyQt5.QtCore import QThread, pyqtSignal
from check_a_license import ZoomClientAutoTest
class WorkThread(QThread):
"""工作线程"""
sinOut = pyqtSignal(list) # 信号槽:和UI主线程通讯, 数据类型str、int、list等
complete_sinOut = pyqtSignal(str) # 测试完成信号槽
def __init__(self):
"""初始化"""
super(WorkThread, self).__init__()
def run(self):
"""线程运行"""
for account_dict in self.account_lists:
time.sleep(1)
sin_out_list = []
username = account_dict["UserName"]
password = account_dict["PassWord"]
buy_sign = account_dict["BuySign"]
account_type = account_dict["AccountType"]
user_type = account_dict["UserType"]
k12 = account_dict["K12"]
role = account_dict["Role"]
sin_out_list.append(account_dict)
try:
z = ZoomClientAutoTest(self.app_path, account_type, role, user_type, k12, username, password, buy_sign)
res = z.run()
sin_out_list.append(str(res))
except Exception as e:
sin_out_list.append(" %s: Error" % username)
self.sinOut.emit(sin_out_list) # 发射信号到主界面
self.complete_sinOut.emit("True")
check_a_license.py
# coding: utf-8
import pytesseract
import os, re, sys, time
import cv2, psutil
from PIL import ImageGrab
from log_module import LogClass
from pywinauto import keyboard, mouse
from pywinauto.application import Application
parent_path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(parent_path)
class ZoomClientAutoTest(LogClass):
"""ZoomClientAutoTest"""
def __init__(self, app_path, account_type, role, user_type, k12, username, password, buy_sign):
"""__init__"""
LogClass.__init__(self, logName='ZoomClientAutoTest')
self.setTimedRotatingFileHandler(fileName='ZoomClientAutoTest') # 日志
self.app_path = app_path # zoom客户端路径
self.img_path = parent_path + "\\IMG\\" # 截图路径
self.account_type = account_type
self.role = role
self.user_type = user_type # 账号信息
self.k12 = k12
self.username = username
self.password = password
self.buy_sign = buy_sign
def start_app(self):
"""start_app"""
app = Application(backend="uia").start(self.app_path) # 启动程序
return app
def get_PID(self, pName):
"""获取 zoom.exe PID"""
p = psutil.process_iter()
for r in p:
aa = str(r)
f = re.compile(pName)
if f.search(aa):
PID = aa.split('pid=')[1].split(',')[0]
return PID
else:
return None
def connect_app(self):
"""根据 zoom PID 绑定程序"""
PID = self.get_PID("Zoom.exe")
# app = Application().connect(path=self.app_path) # 程序路径绑定,常用方法
app = Application().connect(process=PID) # 用于连接已经启动的程序,注意会改变
# app = Application().connect(handle=0x100A6E) # 应用程序的窗口句柄,注意会改变
# app = Application().connect(title_re="Zoom*", class_name="ZPFTEWndClass") # 标题、类型等匹配
return app
def click_before_login_sign_in(self, app):
"""click_before_login_sign_in"""
dlg_spec = app.window(class_name='ZPFTEWndClass') # 定位窗口
dlg_spec.wait("exists ready", timeout=5, retry_interval=3) # 等到窗口真的开着
time.sleep(1)
dlg_spec.window(title=r'Sign In', control_type="Button").click() # 点击Button控件,进入登录界面
return dlg_spec
def login_app(self, dlg_spec, username, password):
"""login_app"""
dlg_spec.wait("exists ready", timeout=5, retry_interval=3) # 等到窗户真的开着
time.sleep(1)
keyboard.send_keys('^a^c') # 全选并剪贴
keyboard.send_keys(username) # 输入用户名
time.sleep(1)
keyboard.send_keys('{VK_TAB}') # 跳转输入框下一行
keyboard.send_keys('^a^c')
keyboard.send_keys(password)
time.sleep(1)
dlg_spec.window(title=r'Sign In', control_type="Button").click()
def main_operation_zoom_interface(self, app, account_type, role, user_type, k12, username, password, buy_sign):
zoom = app.window(class_name=r'ZPPTMainFrmWndClassEx')
zoom.wait("exists ready", timeout=5, retry_interval=3) # 等到窗户真的开着
# zoom.print_control_identifiers() # 打印详细的窗口信息
zoom.window(title=r'最大化', control_type="Button").click() # 注意定位到多个相同title,用control_type区分
time.sleep(2)
mouse.click(coords=(1895, 52)) # 鼠标点击头像 TODO:先写死
time.sleep(2)
coord = (1680, 585, 1885, 605) # 截图 TODO:先写死
im = ImageGrab.grab(coord)
if os.path.exists(self.img_path) is False:
os.makedirs(self.img_path)
im.save(self.img_path + username + ".jpg")
pytesseract.pytesseract.tesseract_cmd = parent_path + '\\Tesseract-OCR\\tesseract.exe'
im = cv2.imread(self.img_path + username + ".jpg")
im_gray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY) # 灰度处理图片
CONFIG = ("-l eng --oem 2 --psm 4")
content = pytesseract.image_to_string(im_gray, config=CONFIG) # 识别图片字母
if str(buy_sign).lower().strip() == "no":
if content == "":
self.logger.info("AccountType:%s | Role:%s | UserType:%s | K12:%s | Username:%s | Password:%s |"
" HaveBuyALicense?:%s | Content:%s | TestResult:%s" % (
account_type, role, user_type, k12, username, password, buy_sign, content, "No"))
result = " %s: Success" % username
else:
self.logger.error("AccountType:%s | Role:%s | UserType:%s | K12:%s | Username:%s | Password:%s |"
" HaveBuyALicense?:%s | Content:%s | TestResult:%s" % (
account_type, role, user_type, k12, username, password, buy_sign, content, "Yes"))
result = " %s: Fail" % username
else:
if content == "":
self.logger.error("AccountType:%s | Role:%s | UserType:%s | K12:%s | Username:%s | Password:%s |"
" HaveBuyALicense?:%s | Content:%s | TestResult:%s" % (
account_type, role, user_type, k12, username, password, buy_sign, content, "No"))
result = " %s: Fail" % username
else:
self.logger.info("AccountType:%s | Role:%s | UserType:%s | K12:%s | Username:%s | Password:%s |"
" HaveBuyALicense?:%s | Content:%s | TestResult:%s" % (
account_type, role, user_type, k12, username, password, buy_sign, content, "Yes"))
result = " %s: Success" % username
time.sleep(2)
mouse.click(coords=(1895, 520)) # switch account TODO:To be optimized
time.sleep(2)
app.kill()
return result
def run(self):
s_app = self.start_app() # 注意:如果软件未启动,启动程序之前将账号退出登录并关闭窗口
# self.connect_app() # 如果软件已启动,连接已经启动的程序 TODO:连接失败,暂不用
dlg_spec = self.click_before_login_sign_in(s_app)
self.login_app(dlg_spec, self.username, self.password) # 登录客户端
res = self.main_operation_zoom_interface(s_app, self.account_type, self.role, self.user_type, self.k12,
self.username, self.password, self.buy_sign)
return res
log_module.py
# coding: utf-8
import os
import sys
import datetime
import logging
from logging import handlers
parent_path = os.path.dirname(os.path.abspath(__file__))
sys.path.append(parent_path)
class LogClass(object):
def __init__(self, logName="ete"):
self.logName = logName
self.logger = logging.getLogger(self.logName)
self.logger.setLevel(logging.DEBUG)
self.now = datetime.datetime.strftime(datetime.datetime.now(), "%Y-%m-%d")
def setTimedRotatingFileHandler(self, path=parent_path + "\\logs", fileName="ete"):
if os.path.exists(path) is False:
os.makedirs(path)
self.fileFullPath = os.path.join(path, self.now + '_' + fileName + ".log")
self.Handlers = handlers.TimedRotatingFileHandler(self.fileFullPath, when='midnight', interval=1,
backupCount=30)
self.Handlers.setLevel(logging.DEBUG)
self.formatter = logging.Formatter(
'[%(asctime)s][%(filename)s][%(lineno)s][%(levelname)s] - [%(message)s]', "%Y-%m-%d %H:%M:%S")
self.Handlers.setFormatter(self.formatter)
self.logger.addHandler(self.Handlers)
return self.logger