Python實(shí)現(xiàn)美化版端口進(jìn)程管理工具
1. 簡介
一個(gè)基于端口管理和進(jìn)程管理的GUI工具,它可以顯示當(dāng)前系統(tǒng)上所有開放的端口信息,并且允許用戶對(duì)選中的進(jìn)程進(jìn)行操作(如結(jié)束進(jìn)程、定位進(jìn)程文件夾路徑、復(fù)制相關(guān)信息到剪貼板等)。
詳細(xì)信息可參考原文信息:基于Python編寫端口進(jìn)程管理工具
2. 運(yùn)行效果
3. 相關(guān)源碼
import sys import psutil import os import pyperclip from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QTableWidget, QTableWidgetItem, QMenu, QAction, QComboBox, QLineEdit, QPushButton, QMessageBox, QHeaderView from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon # 獲取本機(jī)所有開放的端口及對(duì)應(yīng)的進(jìn)程信息 def get_open_ports(): open_ports = [] for conn in psutil.net_connections(kind='inet'): if conn.status != 'LISTEN': continue pid = conn.pid if conn.type == 1: # TCP協(xié)議 protocol = 'TCP' elif conn.type == 2: # UDP協(xié)議 protocol = 'UDP' else: protocol = 'N/A' try: process = psutil.Process(pid) process_name = process.name() exe_path = process.exe() except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess): process_name = "N/A" exe_path = "N/A" open_ports.append({ 'Port': conn.laddr.port, 'PID': pid, 'Process Name': process_name, 'Protocol': protocol, 'Path': exe_path }) return open_ports # 根據(jù)端口號(hào)查詢對(duì)應(yīng)進(jìn)程的信息 def search_by_port(port): open_ports = get_open_ports() for port_info in open_ports: if port_info['Port'] == port: return port_info return None # 根據(jù)進(jìn)程名稱查詢對(duì)應(yīng)的端口信息 def search_by_process_name(name): open_ports = get_open_ports() result = [] for port_info in open_ports: if name.lower() in port_info['Process Name'].lower(): result.append(port_info) return result # 根據(jù)PID查詢對(duì)應(yīng)的端口信息 def search_by_pid(pid): open_ports = get_open_ports() for port_info in open_ports: if port_info['PID'] == pid: return port_info return None # 結(jié)束進(jìn)程 def kill_process(pid): try: process = psutil.Process(pid) process.terminate() # 發(fā)送 terminate 信號(hào) process.wait() # 等待進(jìn)程結(jié)束 return True except (psutil.NoSuchProcess, psutil.AccessDenied): return False # 定位進(jìn)程文件夾路徑 def open_process_folder(exe_path): if exe_path and os.path.exists(exe_path): folder_path = os.path.dirname(exe_path) os.startfile(folder_path) # 打開文件夾 return True return False # 復(fù)制到剪貼板的功能 def copy_to_clipboard(text): pyperclip.copy(text) # 使用 pyperclip 庫復(fù)制文本 class PortProcessManager(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("端口進(jìn)程管理工具") self.setWindowIcon(QIcon(os.path.join(os.getcwd(), 'icon.ico'))) self.setGeometry(100, 100, 900, 600) #self.setWindowOpacity(0.8) # 設(shè)置窗口透明度為0.8 # 主窗口布局 self.main_widget = QWidget() self.setCentralWidget(self.main_widget) layout = QVBoxLayout(self.main_widget) # 搜索框布局 search_layout = QHBoxLayout() self.search_type_combo = QComboBox() self.search_type_combo.addItems(["端口號(hào)", "進(jìn)程名稱", "PID"]) self.search_type_combo.setCurrentIndex(0) search_layout.addWidget(self.search_type_combo) self.search_input = QLineEdit() search_layout.addWidget(self.search_input) self.search_button = QPushButton("查 詢") self.search_button.clicked.connect(self.search) search_layout.addWidget(self.search_button) self.refresh_button = QPushButton("刷新列表") self.refresh_button.clicked.connect(self.refresh_list) search_layout.addWidget(self.refresh_button) layout.addLayout(search_layout) # 表格展示 self.table = QTableWidget() self.table.setColumnCount(5) self.table.setHorizontalHeaderLabels(["PID", "協(xié)議", "端口", "進(jìn)程名稱", "相關(guān)路徑"]) self.table.setEditTriggers(QTableWidget.NoEditTriggers) # 禁止編輯 self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # 列寬自適應(yīng) layout.addWidget(self.table) # 右鍵菜單 self.table.setContextMenuPolicy(Qt.CustomContextMenu) self.table.customContextMenuRequested.connect(self.open_right_menu) # 設(shè)置樣式 self.set_styles() # 初始化數(shù)據(jù) self.refresh_list() def set_styles(self): # 設(shè)置字體為 "Segoe UI" style = """ * { font-family: "Segoe UI"; } QPushButton { background-color: #2dd8e1; color: white; border: 1px solid #00a7c3; padding: 5px; } QHeaderView::section { background-color: #2dd8e1; color: white; padding: 5px; } """ self.setStyleSheet(style) def refresh_list(self): self.table.setRowCount(0) open_ports = get_open_ports() if not open_ports: QMessageBox.information(self, "沒有找到端口", "沒有開放的端口或無法獲取端口信息。") return for port_info in open_ports: row_position = self.table.rowCount() self.table.insertRow(row_position) self.table.setItem(row_position, 0, QTableWidgetItem(str(port_info['PID']))) self.table.setItem(row_position, 1, QTableWidgetItem(port_info['Protocol'])) self.table.setItem(row_position, 2, QTableWidgetItem(str(port_info['Port']))) self.table.setItem(row_position, 3, QTableWidgetItem(port_info['Process Name'])) self.table.setItem(row_position, 4, QTableWidgetItem(port_info['Path'])) def search(self): search_value = self.search_input.text() search_type = self.search_type_combo.currentText() if not search_value: QMessageBox.warning(self, "輸入錯(cuò)誤", "請(qǐng)輸入查詢內(nèi)容!") return self.table.setRowCount(0) if search_type == "端口號(hào)": try: port = int(search_value) port_info = search_by_port(port) if port_info: self.add_row(port_info) else: QMessageBox.information(self, "未找到", f"未找到端口 {port} 對(duì)應(yīng)的進(jìn)程。") except ValueError: QMessageBox.warning(self, "輸入錯(cuò)誤", "請(qǐng)輸入有效的端口號(hào)。") elif search_type == "進(jìn)程名稱": result = search_by_process_name(search_value) if result: for port_info in result: self.add_row(port_info) else: QMessageBox.information(self, "未找到", f"未找到進(jìn)程名稱包含 {search_value} 的記錄。") elif search_type == "PID": try: pid = int(search_value) port_info = search_by_pid(pid) if port_info: self.add_row(port_info) else: QMessageBox.information(self, "未找到", f"未找到PID {pid} 對(duì)應(yīng)的進(jìn)程。") except ValueError: QMessageBox.warning(self, "輸入錯(cuò)誤", "請(qǐng)輸入有效的PID。") def add_row(self, port_info): row_position = self.table.rowCount() self.table.insertRow(row_position) self.table.setItem(row_position, 0, QTableWidgetItem(str(port_info['PID']))) self.table.setItem(row_position, 1, QTableWidgetItem(port_info['Protocol'])) self.table.setItem(row_position, 2, QTableWidgetItem(str(port_info['Port']))) self.table.setItem(row_position, 3, QTableWidgetItem(port_info['Process Name'])) self.table.setItem(row_position, 4, QTableWidgetItem(port_info['Path'])) def open_right_menu(self, pos): selected_item = self.table.itemAt(pos) if selected_item: row = selected_item.row() pid = self.table.item(row, 0).text() port = self.table.item(row, 2).text() process_name = self.table.item(row, 3).text() exe_path = self.table.item(row, 4).text() menu = QMenu(self) kill_action = QAction("結(jié)束進(jìn)程", self) kill_action.triggered.connect(lambda: self.kill_process(int(pid))) menu.addAction(kill_action) folder_action = QAction("定位進(jìn)程文件夾路徑", self) folder_action.triggered.connect(lambda: self.open_folder(exe_path)) menu.addAction(folder_action) copy_pid_action = QAction("復(fù)制PID", self) copy_pid_action.triggered.connect(lambda: copy_to_clipboard(pid)) menu.addAction(copy_pid_action) copy_port_action = QAction("復(fù)制端口號(hào)", self) copy_port_action.triggered.connect(lambda: copy_to_clipboard(port)) menu.addAction(copy_port_action) copy_process_action = QAction("復(fù)制進(jìn)程名稱", self) copy_process_action.triggered.connect(lambda: copy_to_clipboard(process_name)) menu.addAction(copy_process_action) copy_path_action = QAction("復(fù)制相關(guān)路徑", self) copy_path_action.triggered.connect(lambda: copy_to_clipboard(exe_path)) menu.addAction(copy_path_action) menu.exec_(self.table.viewport().mapToGlobal(pos)) def kill_process(self, pid): if kill_process(pid): QMessageBox.information(self, "結(jié)束進(jìn)程", f"進(jìn)程 (PID: {pid}) 已被成功結(jié)束。") else: QMessageBox.warning(self, "錯(cuò)誤", "無法結(jié)束該進(jìn)程,可能沒有權(quán)限。") def open_folder(self, exe_path): if open_process_folder(exe_path): QMessageBox.information(self, "打開文件夾", "已成功定位進(jìn)程文件夾。") else: QMessageBox.warning(self, "錯(cuò)誤", "無法找到進(jìn)程文件路徑。") def keyPressEvent(self, event): if event.key() == Qt.Key_Return: # 檢測到回車鍵 self.search() # 執(zhí)行查詢操作 else: super().keyPressEvent(event) if __name__ == "__main__": app = QApplication(sys.argv) window = PortProcessManager() window.show() sys.exit(app.exec_())
到此這篇關(guān)于Python實(shí)現(xiàn)美化版端口進(jìn)程管理工具的文章就介紹到這了,更多相關(guān)Python端口進(jìn)程管理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
python基于socket函數(shù)實(shí)現(xiàn)端口掃描
這篇文章主要為大家詳細(xì)介紹了python基于socket函數(shù)實(shí)現(xiàn)端口掃描,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05python中使用zip函數(shù)出現(xiàn)<zip object at 0x02A9E418>錯(cuò)誤的原因
這篇文章主要介紹了python中使用zip函數(shù)出現(xiàn)<zip object at 0x02A9E418>錯(cuò)誤的原因分析及解決方法,需要的朋友可以參考下2018-09-09Python使用APScheduler實(shí)現(xiàn)定時(shí)任務(wù)過程解析
這篇文章主要介紹了Python使用APScheduler實(shí)現(xiàn)定時(shí)任務(wù)過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09python學(xué)習(xí)將數(shù)據(jù)寫入文件并保存方法
在本篇文章里小編給大家分享的是關(guān)于python將數(shù)據(jù)寫入文件并保存的實(shí)例內(nèi)容,需要的朋友們可以學(xué)習(xí)下。2020-06-06Django通過dwebsocket實(shí)現(xiàn)websocket的例子
今天小編就為大家分享一篇Django通過dwebsocket實(shí)現(xiàn)websocket的例子,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11Django 實(shí)現(xiàn)xadmin后臺(tái)菜單改為中文
今天小編就為大家分享一篇Django 實(shí)現(xiàn)xadmin后臺(tái)菜單改為中文,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11