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
相关产品推荐
相关产品推荐

