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

Windows下使用subprocess模块调用netsh命令时的字符编码异常问题

Windows下使用subprocess模块调用netsh命令时的字符编码异常问题

看起来你遇到的核心问题是通过subprocess给cmd的stdin发送命令时,netsh对特殊字符的编码解析出现乱码,但直接在CMD里运行相同命令却正常。这本质是因为subprocess的编码设置和CMD、netsh期望的编码不匹配导致的,我来给你梳理下解决方案:

一、问题根源分析

你之前用encoding='utf-8'配置subprocess,但Windows的CMD默认使用的是系统区域对应的OEM编码(比如中文系统是cp936,英文系统是cp437),而netsh在处理输入时会遵循CMD的编码规则。当你用utf-8发送命令时,特殊字符会被错误转码,导致netsh识别不了正确的WiFi配置文件名;而echo能正常显示是因为它只是把输入原封不动输出,subprocess用utf-8读取stdout时又把乱码转回来了,看起来正常,但netsh内部处理已经出错了。

二、最优解决方案:直接调用netsh(避免CMD中转)

其实完全不需要先启动CMD再发命令,直接针对每个WiFi配置文件调用netsh即可,而且通过多线程还能解决你担心的速度问题。

示例代码

import subprocess
import locale
from concurrent.futures import ThreadPoolExecutor

def get_all_wifi_profiles():
    # 获取所有WiFi配置文件名称
    result = subprocess.run(
        ["netsh", "wlan", "show", "profiles"],
        capture_output=True,
        text=True,
        encoding=locale.getpreferredencoding(False)
    )
    profiles = []
    # 适配中英文系统的输出
    for line in result.stdout.splitlines():
        if ("所有用户配置文件" in line or "User profiles" in line) and ":" in line:
            prof_name = line.split(":", 1)[1].strip()
            if prof_name:
                profiles.append(prof_name)
    return profiles

def get_wifi_password(profile_name):
    try:
        # 获取指定WiFi的密码
        result = subprocess.run(
            ["netsh", "wlan", "show", "profiles", f"name={profile_name}", "key=clear"],
            capture_output=True,
            text=True,
            encoding=locale.getpreferredencoding(False),
            timeout=5
        )
        # 提取密码内容
        for line in result.stdout.splitlines():
            if "关键内容" in line or "Key Content" in line:
                return profile_name, line.split(":", 1)[1].strip()
        return profile_name, "无密码或无法获取"
    except Exception as e:
        return profile_name, f"获取失败: {str(e)}"

if __name__ == "__main__":
    all_profiles = get_all_wifi_profiles()
    # 用多线程并行获取,提升速度
    with ThreadPoolExecutor(max_workers=5) as executor:
        results = executor.map(get_wifi_password, all_profiles)
    
    # 打印结果
    print("所有已保存的WiFi信息:")
    for name, pwd in results:
        print(f"名称: {name}, 密码: {pwd}")

为什么这个方法有效?

  • 直接调用netsh,跳过了CMD的中转,编码设置为locale.getpreferredencoding(False),也就是系统控制台的默认编码,和netsh期望的编码完全匹配,特殊字符能正确传递。
  • 用ThreadPoolExecutor并行处理,解决了你担心的逐个调用速度慢的问题,效率会提升很多。

三、如果一定要用CMD批量发送命令的解决方法

如果你坚持要通过CMD的stdin批量发送命令,只需要把subprocess的编码设置为系统默认的控制台编码即可:

import subprocess
import locale

# 获取系统控制台的默认编码
cmd_encoding = locale.getpreferredencoding(False)

process = subprocess.Popen(
    "cmd",  
    stdin=subprocess.PIPE,
    stdout=subprocess.PIPE,
    stderr=subprocess.PIPE,
    text=True,
    encoding=cmd_encoding,
    creationflags=subprocess.CREATE_NO_WINDOW)

# 发送带特殊字符的命令
process.stdin.write(f'netsh wlan show profiles name="Leonard鈥檚 iPhone iP15" key=clear\n')
process.stdin.flush()
process.stdin.write(f'echo test鈥檛est\n')
process.stdin.flush()

stdout, stderr = process.communicate()
print(stdout)

这样发送的命令会用CMD期望的编码传递,netsh就能正确识别WiFi配置文件名了,同时stdout的读取也用相同编码,输出内容也能正常显示。

备注:内容来源于stack exchange,提问作者Mycorrizal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 17:37:57