基于pyqt5的系统信息获取软件
1,主程序
功能概述:主程序主要控制软件的升级和启动
# -*- coding: utf-8 -*-
import os, sys
import win32api
import win32con
import time
import json
import threading
import ctypes
import shutil
from subprocess import *
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMessageBox, QDesktopWidget
'''
思路:下载获取服务器的conf.json文件到temp文件夹
与本地文件夹下conf.josn文件进行版本号比较
若版本号大于本地版本号,则下载exe文件到temp
文件夹,进行更新若匹配,则不进行操作
'''
class MyWindow(QtWidgets.QWidget):
#构造函数
def __init__(self):
super(MyWindow,self).__init__()
self.autoStartUp()
#启动线程下载配置文件,查询是否有新版本
#t1 = threading.Thread(target=self.download('url1'))
#t1.start()
while not(self.isUpdate()):
print('查询是否有更新')
time.sleep(10)
print('软件有更新!')
#t2 = threading.Thread(target=self.download('url2'))
#t2.start()
while True:
if os.path.exists('./temp/BSSmain.exe'):
print('软件已下载完成,正在安装更新!')
self.update()
break #跳出while循环!
print('等待软件下载完成!')
time.sleep(3)
sys.exit(0)
#设置窗口中心显示
def windowCenter(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
#自启动函数
def autoStartUp(self):
(path, name) = os.path.split(sys.argv[0])
path1 = path + '\\bin\\BSSmain.exe'
print(path1)
path2 = path + '\\BSS.exe'
#time.sleep(1)
if os.path.exists(path1):
Popen(path1, creationflags=CREATE_NEW_CONSOLE)
if os.path.exists(path2):
runpath = "Software\\Microsoft\\Windows\\CurrentVersion\\Run"
hKey = win32api.RegOpenKeyEx(win32con.HKEY_CURRENT_USER, runpath, 0, win32con.KEY_SET_VALUE)
#(filepath, filename) = os.path.split(path2)
win32api.RegSetValueEx(hKey, "BSS", 0, win32con.REG_SZ, path2)
win32api.RegCloseKey(hKey)
#下载函数
def download(self, url):
(path, name) = os.path.split(sys.argv[0])
#url = 'http://pic.58pic.com/58pic/15/64/95/00v58PICESr_1024.jpg'
#local是指定的文件存储的目录
local = path + '\\temp'
path = local + url.split('/')[-1]
print(path)
try:
if not os.path.exists(local):
os.mkdir(local)
if not os.path.exists(path):
r = requests.get(url)
with open(path,'wb') as f:
f.write(r.content)
f.close()
print('软件包下载完成')
return 1
else:
print('文件已存在')
return 1
except:
print('爬取失败')
return 0
#判断是否升级函数
def isUpdate(self):
(path, name) = os.path.split(sys.argv[0])
path3 = path + '\\conf.json'
path5 = path + '\\temp\\conf.json'
if os.path.exists(path5):
fileNew = open(path5, encoding='utf-8')
else:
return 0
if os.path.exists(path3):
fileOld = open(path3, encoding='utf-8')
else:
return 0
new = json.load(fileNew)
old = json.load(fileOld)
verN = new['version']
verO = old['version']
fileNew.close()
fileOld.close()
if verN > verO: #若版本号不同,则更新
return 1
else:
return 0
#软件更新函数
def update(self):
(path, name) = os.path.split(sys.argv[0])
path1 = path + '\\bin\\BSSmain.exe'
path3 = path + '\\conf.json'
path4 = path + '\\temp\\BSSmain.exe'
path5 = path + '\\temp\\conf.json'
self.windowCenter()
reply = QMessageBox.information(self, '信息',
'检测到BSS新版本,立即更新!',
QMessageBox.Yes)
if reply == QMessageBox.Yes:
Popen('taskkill /IM BSSmain.exe /F',creationflags=CREATE_NEW_CONSOLE)#直接关闭主进程
time.sleep(5)
#cmd1 = 'replace /r' + ' ' + path4 + ' ' + path
if os.path.exists(path4):
os.remove(path1)
shutil.move(path4, path)
#cmd2 = 'replace /r' + ' ' + path5 + ' ' + path
if os.path.exists(path5):
os.remove(path3)
shutil.move(path5, path)
#Popen(cmd2)
#os.remove(path5)
reply = QMessageBox.information(self,'信息',
'软件已更新完毕!',
QMessageBox.Yes)
if reply == QMessageBox.Yes:
#重新启动exe文件
if os.path.exists(path1):
Popen(path1, creationflags=CREATE_NEW_CONSOLE)
else:
pass
if __name__=="__main__":
app=QtWidgets.QApplication(sys.argv)
myshow=MyWindow()
sys.exit(app.exec_())
2,获取本地信息程序
功能概述:获取电脑的硬件信息以及动态信息
# -*- coding: utf-8 -*-
import sys, os, re, wmi, time
import platform, winreg, psutil
import ctypes, json, subprocess
import win32event, win32con
import win32api, pywintypes
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
class TrayIcon(QSystemTrayIcon):
def __init__(self, parent=None):
super(TrayIcon, self).__init__(parent)
self.showMenu()
self.other()
def showMenu(self):
"设计托盘的菜单"
self.menu = QMenu()
self.quitAction = QAction("退出", self, triggered=self.quit)
self.menu.addAction(self.quitAction)
self.setContextMenu(self.menu)
def other(self):
self.activated.connect(self.iconClied)
#把鼠标点击图标的信号和槽连接
(path, name) = os.path.split(sys.argv[0])
print(path)
self.setIcon(QIcon(path + "\\icon\\icon.png"))
#self.setIcon(QIcon('./icon/icon.png'))
self.icon = self.MessageIcon()
#设置图标
def iconClied(self, reason):
"鼠标点击icon传递的信号会带有一个整形的值,1是表示单击右键,2是双击,3是单击左键,4是用鼠标中键点击"
if reason == 2 or reason == 3:
pw = self.parent()
if pw.isVisible():
pw.hide()
else:
pw.show()
def quit(self):
self.setVisible(False)
self.parent().close()
qApp.quit()
sys.exit()
class MyThread(QThread):
trigger = pyqtSignal()
sec = 300
def __init__(self, parent=None):
super().__init__(parent)
def run(self):
while True:
self.trigger.emit() #循环完毕后发出信号
time.sleep(self.sec)
class BSS(QMainWindow):
def __init__(self):
super(BSS,self).__init__()
self.initUI()
def initUI(self):
(path, name) = os.path.split(sys.argv[0])
self.sysPlatform()
self.login()
self.thread = MyThread()
self.thread.trigger.connect(self.autoPost) # 线程发过来的信号挂接到槽:autoPost
self.thread.start()
exitAction = QAction(QIcon(path + '\\icon\\exitIcon.png'), 'Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit')
exitAction.triggered.connect(self.close)
sysInfo = QAction(QIcon(path + '\\icon\\infoIcon.png'), 'Sys Info', self)
sysInfo.setShortcut('Ctrl+W')
sysInfo.setStatusTip('Sys Info')
sysInfo.triggered.connect(self.sysPlatform)
softList = QAction(QIcon(path + '\\icon\\softIcon.png'), 'Soft List', self)
softList.setShortcut('Ctrl+A')
softList.setStatusTip('Soft List')
softList.triggered.connect(self.softwareList)
procList = QAction(QIcon(path + '\\icon\\procIcon.png'), 'Proc list', self)
procList.setShortcut('Ctrl+S')
procList.setStatusTip('Proc List')
procList.triggered.connect(self.processList)
self.statusBar()
menubar = self.menuBar()
fileMenu = menubar.addMenu('&File')
fileMenu.addAction(exitAction)
toolbar = self.addToolBar('Sys Info')
toolbar.addAction(sysInfo)
toolbar = self.addToolBar('Soft List')
toolbar.addAction(softList)
toolbar = self.addToolBar('Proc List')
toolbar.addAction(procList)
toolbar = self.addToolBar('Exit')
toolbar.addAction(exitAction)
self.setGeometry(300, 300, 700, 450)
self.windowCenter()
self.setWindowTitle('系统基本信息')
self.tray_icon = TrayIcon(self)
self.tray_icon.show()
#重写退出程序,改成只是隐藏界面
def closeEvent(self, event):
self.hide()
event.ignore()
def buttom(self):
# 修改
widget=QWidget()
updateBtn = QPushButton('确定')
updateBtn.setStyleSheet("QPushButton{background-color:black; color:white; border-radius:10px; border:2px groove gray; border-style:outset;}"
"QPushButton:hover{background-color:white; color:black;}"
"QPushButton:pressed{background-color:rgb(85, 170, 255);border-style: inset;}"
);
updateBtn.clicked.connect(lambda:self.post())
hLayout = QHBoxLayout()
hLayout.addWidget(updateBtn)
hLayout.setContentsMargins(5,2,5,2)
widget.setLayout(hLayout)
return widget
def login(self):
#self.sysPlatform()
dock=QDockWidget(self.tr("人员登记"),self)
dock.setFixedSize(150, 450)
dock.setFeatures(QDockWidget.DockWidgetMovable)
dock.setAllowedAreas(Qt.LeftDockWidgetArea|Qt.RightDockWidgetArea)
verticalHeader = ["姓名", "电话", "部门", '定时', '上传']
self.table = QTableWidget()
#self.setCentralWidget(self.table)#注意这个功能很重要,添加各种东西到界面上的接口
self.table.setColumnCount(1)
self.table.setRowCount(5)
self.table.setVerticalHeaderLabels(verticalHeader)
self.table.setEditTriggers(QTableWidget.DoubleClicked)
self.table.setSelectionBehavior(QTableWidget.SelectRows)
self.table.setSelectionMode(QTableWidget.SingleSelection)
self.table.horizontalHeader().setVisible(False)
for index in range(self.table.rowCount()):
headItem = self.table.verticalHeaderItem(index)
self.table.setColumnWidth(0,100)
self.name = QTableWidgetItem("")
self.table.setItem(0,0, self.name)
self.phone = QTableWidgetItem("")
self.table.setItem(0,1, self.phone)
genderComb1 = QComboBox()
self.depat = genderComb1
genderComb1.addItem(r"系统集成部")
genderComb1.addItem(r"电信软件部")
genderComb1.setCurrentIndex(0)
self.table.setCellWidget(2,0,genderComb1)
genderComb2 = QComboBox()
self.timing = genderComb2
genderComb2.addItem("5min")
genderComb2.addItem("10min")
genderComb2.addItem("15min")
genderComb2.setCurrentIndex(0)
self.table.setCellWidget(3,0,genderComb2)
self.table.setCellWidget(4,0,self.buttom())
#停靠窗口
dock.setWidget(self.table)
self.addDockWidget(Qt.RightDockWidgetArea,dock)
def windowCenter(self):
qr = self.frameGeometry()
cp = QDesktopWidget().availableGeometry().center()
qr.moveCenter(cp)
self.move(qr.topLeft())
def post(self):
#获取文本框内容
(path, name) = os.path.split(sys.argv[0])
name = self.name.text()
self.postData['name'] = str(name)
phone = self.phone.text()
self.postData['phone'] = str(phone)
depat = self.depat.currentText()
self.postData['depat'] = depat
print(self.postData)
postJsonData = json.dumps(self.postData, ensure_ascii=False)
f = open(path + '\\upload\\info.json', 'w')
print(postJsonData)
f.write(postJsonData)
f.close()
timing = self.timing.currentText()
#定时上传数据
self.thread.terminate()
if timing == '5min':
self.thread = MyThread() # 创建一个线程
elif timing == '10min':
self.thread = MyThread()
self.thread.sec = 600
else:
self.thread = MyThread()
self.thread.sec = 900
self.thread.trigger.connect(self.autoPost) # 线程发过来的信号挂接到槽:autoPost
self.thread.start()
#手动上传系统信息及个人信息
print('上传成功!')
def sysPlatform(self):
self.textE1 = QTextEdit()
self.textE1.setFontPointSize(16)
self.textE1.setFontWeight(75)
self.textE1.setText('系统硬件配置参数')
self.setCentralWidget(self.textE1)
self.textE1.setFontWeight(50)
self.textE1.setFontPointSize(11)
self.postData = {}
key = ['操作系统', '操作系统的位数', 'cpu型号', '网卡', 'IP地址', 'mac地址', '硬盘', '键盘', '主板', '声卡', '显示器', '显卡']
val = []
#操作系统
pf = platform.platform()
#cpu型号
w = wmi.WMI()
cpu = w.Win32_Processor()[0]
#硬盘
dd = w.Win32_DiskDrive()[0]
#键盘
kb = w.Win32_Keyboard()[0]
#主板
bb = w.Win32_BaseBoard()[0]
#声卡
sd = w.Win32_SoundDevice()[0]
#显示器
dm = w.Win32_DesktopMonitor()[0]
#显卡
dp = w.Win32_DisplayConfiguration()[0]
#网卡
nw = w.Win32_NetworkAdapter()[0]
#网卡ip和mac地址
adr = []
nd = psutil.net_if_addrs()
for k, v in nd.items():
for item in v:
if item[0] == 2 and not item[1]=='127.0.0.1':
adr.append((k, item[1]))#ip地址
if '-' in item[1] and len(item[1])==17:
adr.append((k, item[1]))#mac地址
val.append(pf)
self.postData['os'] = pf
val.append(str(cpu.AddressWidth) + 'bit')
self.postData['osAddressWidth'] = cpu.AddressWidth
val.append(cpu.Name)
self.postData['cpu'] = cpu.Name
val.append(nw.Name)
self.postData['netWorkCard'] = nw.Name
val.append(adr[1][1])
self.postData['ip'] = adr[1][1]
val.append(adr[0][1])
self.postData['mac'] = adr[0][1]
val.append(dd.Caption)
self.postData['diskDrive'] = dd.Caption
val.append(kb.Caption)
self.postData['keyBoard'] = kb.Caption
val.append(bb.Product)
self.postData['baseBoard'] = bb.Product
val.append(sd.Name)
self.postData['soundDevice'] = sd.Name
val.append(dm.Name)
self.postData['monitor'] = dm.Name
val.append(dp.Caption)
self.postData['graphicsCard'] = dp.Caption
for i, j in zip(key, val):
item = i + ' = ' + j
self.textE1.append(item)
self.textE1.setFontPointSize(16)
self.textE1.setFontWeight(75)
self.textE1.append('系统动态信息')
self.textE1.setFontWeight(50)
self.textE1.setFontPointSize(11)
#cpu运行情况
cpu = psutil.cpu_times_percent(interval=1.00)
item = 'cpu占用情况 : ' + '用户 : ' + str(cpu.user) + '%' + ' 系统 : ' + str(cpu.system) + '%' + ' 空闲 : ' + str(cpu.idle) + '%'
self.textE1.append(item)
self.autoPostData = {}
data = {'user':cpu.user, 'system':cpu.system, 'idle':cpu.idle, 'interrupt':cpu.interrupt, 'dpc':cpu.dpc}
self.autoPostData['cpuUsePercentage'] = data
self.postData['cpuUsePercentage'] = data
#运行内存大小
men = psutil.virtual_memory()
item = '内存大小 : ' + str(round(men.total/1024/1024/1024)) + 'g' + ' 已占用 : ' + str(round(men.used/1024/1024/1024, 2)) + 'g' + ' 占用率 : ' + str(round(men.percent, 1))+'%'
self.textE1.append(item)
self.autoPostData['memoryUsePercentage'] = round(men.percent, 1)
self.postData['memoryUsePercentage'] = round(men.percent, 1)
#各分区
dev = []
total = []
free = []
used = []
per = []
p = psutil.disk_partitions()
j = 0
for i in p:
if (str(p[j].fstype) != ''):
dev.append(str(p[j].device))
#print(psutil.disk_usage(str(p[j].device))) #获取各个分区的状态
total.append(str(round(psutil.disk_usage(str(p[j].device)).total/1024/1024/1024)) + 'g')
free.append(str(round(psutil.disk_usage(str(p[j].device)).free/1024/1024/1024)) + 'g')
used.append(str(round(psutil.disk_usage(str(p[j].device)).used/1024/1024/1024)) + 'g')
per.append(str(round(psutil.disk_usage(str(p[j].device)).percent, 1)) + '%')
item = '盘符 : ' + dev[j] + ' 总共 : ' + total[j] + ' 剩余 : ' +free[j] + ' 已使用 : ' + used[j] + ' 使用率 : ' + per[j]
self.textE1.append(item)
j += 1
diskIoCounters = psutil.disk_io_counters()
item = '硬盘读取情况 : ' + str(diskIoCounters)
self.textE1.append(item)
self.textE1.setReadOnly(True)
data = {'read_count':diskIoCounters.read_count, 'write_count':diskIoCounters.write_count, 'read_bytes':diskIoCounters.read_bytes, \
'write_bytes':diskIoCounters.write_bytes, 'read_time':diskIoCounters.read_time, 'write_time':diskIoCounters.write_time}
self.autoPostData['diskIoCounters'] = data
self.postData['diskIoCounters'] = data
def softwareList(self):
data = []
self.textE2 = QTextEdit()
self.textE2.setFontPointSize(16)
self.textE2.setFontWeight(75)
self.textE2.setText('系统安装软件列表')
self.setCentralWidget(self.textE2)
self.textE2.setFontWeight(50)
self.textE2.setFontPointSize(11)
sub_key=[r'SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall', r'SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall']
for k in sub_key:
try:
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, k, 1, winreg.KEY_READ)
i = winreg.QueryInfoKey(key)[0]-1
#print('i = ', i)
for j in range(0,i):
#print('j = ', j)
subkey_name = winreg.EnumKey(key, j)
#print(subkey_name)
subkey = winreg.OpenKey(key, subkey_name)
#print(subkey)
try:
#m = winreg.QueryInfoKey(subkey)[1]
#for n in range(0, m):
# temp = winreg.EnumValue(subkey, n)
# self.textE2.append(str(temp))
# data.append(temp)
displayname,d = winreg.QueryValueEx(subkey, u'DisplayName')
self.textE2.append('DisplayName = ' + displayname)
#displayVersion,d = winreg.QueryValueEx(subkey, u'DisplayVersion')
#self.textE2.append('DisplayVersion = ' + displayVersion)
#
#Publisher,d = winreg.QueryValueEx(subkey, u'Publisher')
#self.textE2.append('Publisher = ' + Publisher)
#
#InstallLocation,d = winreg.QueryValueEx(subkey, u'InstallLocation')
#self.textE2.append('InstallLocation = ' + InstallLocation)
#
#UninstallString,d = winreg.QueryValueEx(subkey, u'UninstallString')
#self.textE2.append('UninstallString = ' + UninstallString)
except Exception:
pass
#self.textE2.append('')
winreg.CloseKey(subkey)
except WindowsError:
pass
finally:
self.textE2.append('----------------------------------------')
self.textE2.append('----------------------------------------')
self.textE2.setReadOnly(True)
def processList(self):
p = []
self.textE3 = QTextEdit()
self.textE3.setFontPointSize(16)
self.textE3.setFontWeight(75)
self.textE3.setText('系统正在运行的程序')
self.setCentralWidget(self.textE3)
self.textE3.setFontWeight(50)
self.textE3.setFontPointSize(11)
for proc in psutil.process_iter():
try:
pinfo = proc.as_dict(attrs=['name', 'pid'])
p.append(pinfo)
except psutil.NoSuchProcess:
pass
else:
self.textE3.append(str(pinfo))
self.textE3.setReadOnly(True)
def autoPost(self):
(path, name) = os.path.split(sys.argv[0])
p = []
for proc in psutil.process_iter():
try:
pinfo = proc.as_dict(attrs=['name', 'pid'])
p.append(pinfo)
except psutil.NoSuchProcess:
pass
self.autoPostData['process'] = p
postJsonData = json.dumps(self.autoPostData, ensure_ascii=False)
f = open(path + '\\upload\\sysDynaInfo.json', 'w')
f.write(postJsonData)
f.close()
if __name__ == '__main__':
ERROR_ALREADY_EXISTS = 183
sz_mutex = "BSS_mutex"
hmutex = win32event.CreateMutex(None, pywintypes.FALSE,sz_mutex)
if (win32api.GetLastError() == ERROR_ALREADY_EXISTS):
sys.exit(0)
else:
time.sleep(0.5)
app = QApplication(sys.argv)
ex = BSS()
sys.exit(app.exec_())