Python 获取 USB 设备信息
在 Python 中,有几种方法可以获取连接到计算机的 USB 设备信息。以下是几种常用的方法:
方法一:使用 pyusb 库
import usb.core
import usb.util
# 列出所有 USB 设备
devices = usb.core.find(find_all=True)
for device in devices:
print(f"设备: {device}")
print(f"ID: {hex(device.idVendor)}:{hex(device.idProduct)}")
print(f"制造商: {usb.util.get_string(device, device.iManufacturer)}")
print(f"产品: {usb.util.get_string(device, device.iProduct)}")
print("-" * 40)
安装 pyusb:
pip install pyusb
方法二:使用 psutil 库(跨平台)
import psutil
# 获取所有 USB 设备
usb_devices = [d for d in psutil.disk_partitions() if 'removable' in d.opts]
for device in usb_devices:
print(f"设备: {device.device}")
print(f"挂载点: {device.mountpoint}")
print(f"文件系统类型: {device.fstype}")
print(f"选项: {device.opts}")
print("-" * 40)
安装 psutil:
pip install psutil
方法三:在 Windows 上使用 WMI
import wmi
c = wmi.WMI()
# 获取 USB 设备
for device in c.Win32_USBControllerDevice():
print(f"设备ID: {device.Dependent.PNPDeviceID}")
print(f"描述: {device.Dependent.Description}")
print(f"状态: {device.Dependent.Status}")
print("-" * 40)
安装 WMI:
pip install wmi
方法四:在 Linux 上使用 lsusb 命令
import subprocess result = subprocess.run(['lsusb'], stdout=subprocess.PIPE) print(result.stdout.decode('utf-8'))
方法五:使用 platform-specific 方法
Windows 版本
import winreg
def get_usb_devices():
devices = []
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
key = winreg.OpenKey(reg, r"SYSTEM\CurrentControlSet\Enum\USB")
for i in range(winreg.QueryInfoKey(key)[0]):
subkey_name = winreg.EnumKey(key, i)
subkey = winreg.OpenKey(key, subkey_name)
for j in range(winreg.QueryInfoKey(subkey)[0]):
subsubkey_name = winreg.EnumKey(subkey, j)
devices.append(f"{subkey_name}\\{subsubkey_name}")
return devices
usb_devices = get_usb_devices()
for device in usb_devices:
print(device)
Linux 版本
import os def get_usb_devices(): return [d for d in os.listdir('/dev') if d.startswith('sd')] usb_devices = get_usb_devices() print("连接的USB存储设备:", usb_devices)
方法六:使用 pyudev (Linux)
import pyudev
context = pyudev.Context()
for device in context.list_devices(subsystem='usb'):
print(f"设备: {device.device_node}")
print(f"厂商ID: {device.get('ID_VENDOR_ID')}")
print(f"产品ID: {device.get('ID_MODEL_ID')}")
print(f"厂商: {device.get('ID_VENDOR')}")
print(f"产品: {device.get('ID_MODEL')}")
print("-" * 40)
安装 pyudev:
pip install pyudev
局域网U盘/硬盘连接记录系统
下面提供一个完整的解决方案,包含PyQt图形界面、客户端和服务器功能。这个系统将允许用户通过图形界面查看所有局域网内主机的U盘/硬盘连接记录。
系统架构
-
服务器端:接收并存储所有客户端的USB连接记录
-
客户端:监控本地USB设备变化并上报服务器
-
管理界面:PyQt实现的GUI,用于查看和分析记录
完整代码实现
1. 服务器端 (带PyQt界面)
# server_gui.py
import sys
import socket
import sqlite3
from datetime import datetime
import threading
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QHBoxLayout, QTableWidget, QTableWidgetItem,
QLabel, QPushButton, QComboBox, QLineEdit)
from PyQt5.QtCore import QTimer, Qt
class USBServerGUI(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("USB设备连接监控服务器")
self.setGeometry(100, 100, 800, 600)
self.create_database()
self.init_ui()
self.start_server()
def create_database(self):
self.conn = sqlite3.connect('usb_logs.db')
self.c = self.conn.cursor()
self.c.execute('''CREATE TABLE IF NOT EXISTS usb_connections
(id INTEGER PRIMARY KEY AUTOINCREMENT,
host_ip TEXT,
host_name TEXT,
device_name TEXT,
device_serial TEXT,
connection_time DATETIME,
event_type TEXT)''')
self.conn.commit()
def init_ui(self):
main_widget = QWidget()
layout = QVBoxLayout()
# 控制面板
control_panel = QWidget()
control_layout = QHBoxLayout()
self.status_label = QLabel("服务器状态: 运行中")
self.refresh_btn = QPushButton("刷新数据")
self.refresh_btn.clicked.connect(self.load_data)
self.filter_host = QComboBox()
self.filter_host.addItem("所有主机")
self.filter_host.currentTextChanged.connect(self.load_data)
self.filter_event = QComboBox()
self.filter_event.addItem("所有事件")
self.filter_event.addItem("已连接")
self.filter_event.addItem("已断开")
self.filter_event.currentTextChanged.connect(self.load_data)
self.search_input = QLineEdit()
self.search_input.setPlaceholderText("搜索设备名称或序列号...")
self.search_input.textChanged.connect(self.load_data)
control_layout.addWidget(self.status_label)
control_layout.addWidget(QLabel("筛选主机:"))
control_layout.addWidget(self.filter_host)
control_layout.addWidget(QLabel("筛选事件:"))
control_layout.addWidget(self.filter_event)
control_layout.addWidget(QLabel("搜索:"))
control_layout.addWidget(self.search_input)
control_layout.addWidget(self.refresh_btn)
control_panel.setLayout(control_layout)
# 数据表格
self.table = QTableWidget()
self.table.setColumnCount(6)
self.table.setHorizontalHeaderLabels(["ID", "主机名", "IP地址", "设备名称", "事件类型", "连接时间"])
self.table.setColumnWidth(0, 50)
self.table.setColumnWidth(1, 150)
self.table.setColumnWidth(2, 120)
self.table.setColumnWidth(3, 200)
self.table.setColumnWidth(4, 80)
self.table.setColumnWidth(5, 150)
layout.addWidget(control_panel)
layout.addWidget(self.table)
main_widget.setLayout(layout)
self.setCentralWidget(main_widget)
# 定时刷新数据
self.timer = QTimer()
self.timer.timeout.connect(self.load_data)
self.timer.start(5000) # 5秒刷新一次
# 初始加载数据
self.load_data()
def load_data(self):
host_filter = self.filter_host.currentText()
event_filter = self.filter_event.currentText()
search_text = self.search_input.text().strip()
query = "SELECT id, host_name, host_ip, device_name, event_type, connection_time FROM usb_connections"
conditions = []
if host_filter != "所有主机":
conditions.append(f"host_name = '{host_filter}'")
if event_filter != "所有事件":
conditions.append(f"event_type = '{event_filter.lower()}'")
if search_text:
conditions.append(f"(device_name LIKE '%{search_text}%' OR device_serial LIKE '%{search_text}%')")
if conditions:
query += " WHERE " + " AND ".join(conditions)
query += " ORDER BY connection_time DESC"
self.c.execute(query)
data = self.c.fetchall()
self.table.setRowCount(len(data))
for row_idx, row_data in enumerate(data):
for col_idx, col_data in enumerate(row_data):
item = QTableWidgetItem(str(col_data))
item.setFlags(item.flags() ^ Qt.ItemIsEditable)
self.table.setItem(row_idx, col_idx, item)
# 更新主机筛选列表
self.update_host_list()
def update_host_list(self):
current_host = self.filter_host.currentText()
self.filter_host.clear()
self.filter_host.addItem("所有主机")
self.c.execute("SELECT DISTINCT host_name FROM usb_connections ORDER BY host_name")
hosts = [host[0] for host in self.c.fetchall()]
for host in hosts:
self.filter_host.addItem(host)
# 恢复之前的选择
if current_host in [self.filter_host.itemText(i) for i in range(self.filter_host.count())]:
self.filter_host.setCurrentText(current_host)
def start_server(self):
self.server_thread = threading.Thread(target=self.run_server, daemon=True)
self.server_thread.start()
def run_server(self):
host = '0.0.0.0'
port = 65432
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.bind((host, port))
s.listen()
while True:
conn, addr = s.accept()
client_thread = threading.Thread(
target=self.handle_client,
args=(conn, addr),
daemon=True
)
client_thread.start()
def handle_client(self, conn, addr):
try:
while True:
data = conn.recv(1024).decode('utf-8')
if not data:
break
parts = data.split('|')
if len(parts) == 4:
host_name, device_name, serial, event_type = parts
self.c.execute(
"INSERT INTO usb_connections (host_ip, host_name, device_name, device_serial, connection_time, event_type) VALUES (?, ?, ?, ?, ?, ?)",
(addr[0], host_name, device_name, serial, datetime.now(), event_type)
)
self.conn.commit()
except Exception as e:
print(f"Error with {addr}: {e}")
finally:
conn.close()
def closeEvent(self, event):
self.conn.close()
event.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = USBServerGUI()
window.show()
sys.exit(app.exec_())
2. 客户端 (带PyQt界面)
# client_gui.py
import sys
import socket
import platform
import getpass
import time
import winreg
from datetime import datetime
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QLabel, QPushButton, QTextEdit, QLineEdit)
from PyQt5.QtCore import QTimer, Qt
class USBClientGUI(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("USB设备监控客户端")
self.setGeometry(100, 100, 500, 400)
self.server_ip = "192.168.1.100" # 默认服务器IP
self.host_name = platform.node()
self.last_devices = set()
self.init_ui()
self.start_monitoring()
def init_ui(self):
main_widget = QWidget()
layout = QVBoxLayout()
# 服务器设置
server_panel = QWidget()
server_layout = QHBoxLayout()
server_layout.addWidget(QLabel("服务器IP:"))
self.server_input = QLineEdit(self.server_ip)
self.apply_btn = QPushButton("应用")
self.apply_btn.clicked.connect(self.update_server_ip)
server_layout.addWidget(self.server_input)
server_layout.addWidget(self.apply_btn)
server_panel.setLayout(server_layout)
# 状态显示
self.status_label = QLabel("状态: 正在监控USB设备...")
self.log_area = QTextEdit()
self.log_area.setReadOnly(True)
# 控制按钮
self.toggle_btn = QPushButton("暂停监控")
self.toggle_btn.clicked.connect(self.toggle_monitoring)
layout.addWidget(server_panel)
layout.addWidget(self.status_label)
layout.addWidget(self.log_area)
layout.addWidget(self.toggle_btn)
main_widget.setLayout(layout)
self.setCentralWidget(main_widget)
# 监控定时器
self.monitor_timer = QTimer()
self.monitor_timer.timeout.connect(self.check_usb_devices)
self.monitor_timer.start(3000) # 3秒检查一次
def update_server_ip(self):
new_ip = self.server_input.text().strip()
if new_ip:
self.server_ip = new_ip
self.log(f"服务器IP已更新为: {self.server_ip}")
def toggle_monitoring(self):
if self.monitor_timer.isActive():
self.monitor_timer.stop()
self.toggle_btn.setText("开始监控")
self.status_label.setText("状态: 监控已暂停")
self.log("USB设备监控已暂停")
else:
self.monitor_timer.start(3000)
self.toggle_btn.setText("暂停监控")
self.status_label.setText("状态: 正在监控USB设备...")
self.log("USB设备监控已恢复")
def log(self, message):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.log_area.append(f"[{timestamp}] {message}")
def start_monitoring(self):
self.log(f"USB设备监控客户端已启动 (主机名: {self.host_name})")
self.log(f"正在连接服务器: {self.server_ip}")
def check_usb_devices(self):
try:
current_devices = set()
if platform.system() == 'Windows':
try:
reg = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
key = winreg.OpenKey(reg, r"SYSTEM\CurrentControlSet\Enum\USBSTOR")
for i in range(winreg.QueryInfoKey(key)[0]):
subkey_name = winreg.EnumKey(key, i)
subkey = winreg.OpenKey(key, subkey_name)
for j in range(winreg.QueryInfoKey(subkey)[0]):
subsubkey_name = winreg.EnumKey(subkey, j)
subsubkey = winreg.OpenKey(subkey, subsubkey_name)
try:
device_name = winreg.QueryValueEx(subsubkey, "FriendlyName")[0]
device_serial = subsubkey_name.split('&')[0]
current_devices.add((device_name, device_serial))
except WindowsError:
continue
except WindowsError:
pass
# 检测新设备
new_devices = current_devices - self.last_devices
for device in new_devices:
self.log(f"检测到新设备: {device[0]} (序列号: {device[1]})")
self.send_usb_event(device[0], device[1], 'connected')
# 检测移除的设备
removed_devices = self.last_devices - current_devices
for device in removed_devices:
self.log(f"设备已移除: {device[0]} (序列号: {device[1]})")
self.send_usb_event(device[0], device[1], 'disconnected')
self.last_devices = current_devices
except Exception as e:
self.log(f"监控错误: {str(e)}")
def send_usb_event(self, device_name, device_serial, event_type):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((self.server_ip, 65432))
data = f"{self.host_name}|{device_name}|{device_serial}|{event_type}"
s.sendall(data.encode('utf-8'))
except Exception as e:
self.log(f"无法连接到服务器: {str(e)}")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = USBClientGUI()
window.show()
sys.exit(app.exec_())
部署说明
-
服务器端部署:
-
在一台始终在线的机器上运行
server_gui.py
-
确保防火墙允许65432端口的TCP连接
-
界面将显示所有客户端的USB连接记录
-
-
客户端部署:
-
在所有需要监控的Windows机器上安装
client_gui.py
-
修改默认服务器IP为实际服务器IP
-
可以设置为开机启动
-
-
功能特点:
-
服务器端实时显示所有USB连接事件
-
支持按主机名、事件类型筛选
-
支持关键词搜索
-
客户端可暂停/恢复监控
-
客户端可修改服务器IP
-
功能迭代
-
安全性增强:
-
添加客户端认证机制
-
使用SSL加密通信
-
-
功能扩展:
-
添加邮件/短信通知功能
-
实现数据导出(Excel, CSV)
-
添加图表统计功能
-
-
跨平台支持:
-
添加Linux/macOS的USB监控实现
-
-
安装程序:
-
使用PyInstaller打包为可执行文件
-
创建安装程序包
-
这个完整实现提供了图形化的监控解决方案,适合企业或组织内部使用,可以有效监控局域网内所有主机的USB设备连接情况。