You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Qt/PySide2扫描范围内所有可用WiFi并连接指定网络

基于PySide2的WiFi扫描与连接实现方案

你当前使用的QNetworkConfigurationManager仅能获取系统中已保存的网络配置记录,无法触发实时WiFi扫描,也无法返回未保存过的周边热点数据,因此会出现Discovered等状态无返回结果的问题。

Qt原生没有提供跨桌面平台的实时WiFi扫描接口,我们可以通过封装不同平台的系统命令,结合PySide2的信号槽机制实现需求,完整实现代码如下:

核心工具类实现

import subprocess
import sys
import os
from PySide2.QtCore import QObject, Signal, Slot

class WifiManager(QObject):
    # 扫描完成信号,返回格式:[(热点名, 信号强度, 加密类型), ...]
    scan_finished = Signal(list)
    # 连接完成信号,返回布尔值标识是否连接成功
    connect_finished = Signal(bool)

    def __init__(self, parent=None):
        super().__init__(parent)
    
    @Slot()
    def start_scan(self):
        """启动实时WiFi扫描"""
        wifi_list = []
        if sys.platform == "win32":
            # Windows平台调用netsh命令扫描
            result = subprocess.run(
                ["netsh", "wlan", "show", "networks", "mode=Bssid"],
                capture_output=True,
                text=True,
                encoding="gbk"
            )
            output = result.stdout
            current_ssid = ""
            current_auth = ""
            for line in output.split("\n"):
                line = line.strip()
                if line.startswith("SSID") and "BSSID" not in line:
                    current_ssid = line.split(":", 1)[1].strip()
                elif line.startswith("身份验证"):
                    current_auth = line.split(":", 1)[1].strip()
                elif line.startswith("信号"):
                    signal = line.split(":", 1)[1].strip()
                    # 去重,只保留每个SSID的第一条记录
                    if current_ssid and current_ssid not in [item[0] for item in wifi_list]:
                        wifi_list.append((current_ssid, signal, current_auth))
        elif sys.platform == "linux":
            # Linux平台调用iwlist扫描,需替换为你的无线网卡名(可通过iw dev查询)
            result = subprocess.run(
                ["iwlist", "wlan0", "scan"],
                capture_output=True,
                text=True
            )
            output = result.stdout
            # 解析逻辑可参考Windows自行补充
        elif sys.platform == "darwin":
            # Mac平台调用airport工具扫描
            result = subprocess.run(
                ["/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport", "-s"],
                capture_output=True,
                text=True
            )
            output = result.stdout
            # 解析逻辑可参考Windows自行补充
        self.scan_finished.emit(wifi_list)
    
    @Slot(str, str)
    def connect_to_wifi(self, ssid: str, password: str):
        """连接指定SSID的WiFi,仅支持WPA2-PSK加密类型,其他类型可自行修改对应配置"""
        success = False
        if sys.platform == "win32":
            # 生成Windows WiFi配置文件
            profile_content = f"""<?xml version="1.0"?>
<WLANProfile xmlns="http://www.microsoft.com/networking/WLAN/profile/v1">
    <name>{ssid}</name>
    <SSIDConfig>
        <SSID>
            <name>{ssid}</name>
        </SSID>
    </SSIDConfig>
    <connectionType>ESS</connectionType>
    <connectionMode>auto</connectionMode>
    <MSM>
        <security>
            <authEncryption>
                <authentication>WPA2PSK</authentication>
                <encryption>AES</encryption>
                <useOneX>false</useOneX>
            </authEncryption>
            <sharedKey>
                <keyType>passPhrase</keyType>
                <protected>false</protected>
                <keyMaterial>{password}</keyMaterial>
            </sharedKey>
        </security>
    </MSM>
</WLANProfile>"""
            temp_file = f"{ssid}_wifi_profile.xml"
            with open(temp_file, "w", encoding="utf-8") as f:
                f.write(profile_content)
            # 添加WiFi配置到系统
            subprocess.run(
                ["netsh", "wlan", "add", "profile", f"filename={temp_file}"],
                capture_output=True
            )
            # 执行连接
            res = subprocess.run(
                ["netsh", "wlan", "connect", f"name={ssid}"],
                capture_output=True
            )
            success = res.returncode == 0
            os.remove(temp_file)
        elif sys.platform == "linux":
            # Linux用NetworkManager的nmcli命令连接
            res = subprocess.run(
                ["nmcli", "dev", "wifi", "connect", ssid, "password", password],
                capture_output=True
            )
            success = res.returncode == 0
        elif sys.platform == "darwin":
            # Mac用networksetup命令连接,en0为默认无线网卡名,可根据实际情况修改
            res = subprocess.run(
                ["networksetup", "-setairportnetwork", "en0", ssid, password],
                capture_output=True
            )
            success = res.returncode == 0
        self.connect_finished.emit(success)

使用示例

from PySide2.QtWidgets import (QApplication, QWidget, QVBoxLayout, QPushButton, 
                               QListWidget, QInputDialog, QMessageBox, QLineEdit)

if __name__ == "__main__":
    app = QApplication([])
    window = QWidget()
    window.setWindowTitle("WiFi扫描工具")
    layout = QVBoxLayout(window)
    
    wifi_manager = WifiManager()
    wifi_list_widget = QListWidget()
    scan_btn = QPushButton("扫描周边WiFi")
    
    # 扫描结果回调
    def handle_scan_result(wifi_list):
        wifi_list_widget.clear()
        for ssid, signal, auth in wifi_list:
            wifi_list_widget.addItem(f"热点名:{ssid} | 信号:{signal} | 加密:{auth}")
    
    # 点击列表项触发连接
    def handle_item_clicked(item):
        ssid = item.text().split("|")[0].replace("热点名:", "").strip()
        password, ok = QInputDialog.getText(window, "连接WiFi", f"请输入{ssid}的密码:", echo=QLineEdit.Password)
        if ok and password:
            wifi_manager.connect_to_wifi(ssid, password)
    
    # 连接结果回调
    def handle_connect_result(success):
        if success:
            QMessageBox.information(window, "提示", "连接成功")
        else:
            QMessageBox.warning(window, "提示", "连接失败,请检查密码或热点状态")
    
    scan_btn.clicked.connect(wifi_manager.start_scan)
    wifi_manager.scan_finished.connect(handle_scan_result)
    wifi_list_widget.itemClicked.connect(handle_item_clicked)
    wifi_manager.connect_finished.connect(handle_connect_result)
    
    layout.addWidget(scan_btn)
    layout.addWidget(wifi_list_widget)
    window.resize(600, 400)
    window.show()
    app.exec_()

注意事项

  • Windows平台运行时需要以管理员身份启动程序,否则扫描结果可能不完整
  • Linux平台需确保已安装wireless-tools和network-manager包,无线网卡名称可通过iw dev命令查询替换代码中的wlan0
  • 示例默认仅支持WPA2-PSK加密的热点,如需支持WEP、开放网络等类型,可修改对应平台的配置参数

内容的提问来源于stack exchange,提问作者Ahmad Mansoori

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 17:45:01