注释(关于 [PyPI]: 无线电):
因此,建议寻找替代方案:
最近遇到的一个是
Win32Wifi:(
[PyPI]:win32wifi,不过这个也没有更新自2017年以来)。更多细节请参见
[SO]:无法使用Python的WlanGetAvailableNetworkList获取所有可用网络(@CristiFati的答案)(还可以查看
[SO]:使用WlanScan在Python中强制进行wifi扫描(@CristiFati的答案))。
,我成功找到了一些内容。
code00.py:
import ctypes as ct
import sys
import time
import traceback
import comtypes
sys.path.insert(0, "e:\Work\Dev\GitHub\CristiFati\win32wifi")
from win32wifi import Win32Wifi as ww
ERROR_SUCCESS = 0
WLAN_CONNECTION_HIDDEN_NETWORK = 0x00000001
class WLANException(Exception): pass
class ConnectCallbackContext(ct.Structure):
_fields_ = [
("guid", ct.c_wchar_p),
("start", ct.c_byte),
("end", ct.c_byte),
("fail", ct.c_byte),
]
def _wlan_connect_callback(data, context_addr):
if context_addr:
context = ConnectCallbackContext.from_address(context_addr)
if str(data.interfaceGuid) == context.guid and data.notificationSource == ww.WLAN_NOTIFICATION_SOURCE_DICT[ww.WLAN_NOTIFICATION_SOURCE_ACM]:
if data.notificationCode == ww.WLAN_NOTIFICATION_ACM_ENUM.wlan_notification_acm_connection_start.name:
context.start += 1
elif context.start:
if data.notificationCode == ww.WLAN_NOTIFICATION_ACM_ENUM.wlan_notification_acm_connection_complete.name:
context.end += 1
elif data.notificationCode == ww.WLAN_NOTIFICATION_ACM_ENUM.wlan_notification_acm_connection_attempt_fail.name:
context.fail += 1
def wireless_connect(
ssid,
password,
timeout=15,
authentication="WPA2PSK",
encryption="AES",
key_type="passPhrase",
interface_index=0,
):
interfaces = ww.getWirelessInterfaces()
if interface_index < 0 or len(interfaces) < interface_index:
raise WLANException(-1, "No WLAN interface for given index")
interface = interfaces[interface_index]
profile_name = ssid + "_profile_tmp"
ssid_hex = "".join((hex(ord(c))[2:] for c in ssid)).upper()
profile_string = f"""<?xml version=\"1.0\"?>
<WLANProfile xmlns=\"http://www.microsoft.com/networking/WLAN/profile/v1\">
<name>{profile_name}</name>
<SSIDConfig>
<SSID>
<hex>{ssid_hex}</hex>
<name>{ssid}</name>
</SSID>
</SSIDConfig>
<connectionType>ESS</connectionType>
<connectionMode>manual</connectionMode>
<MSM>
<security>
<authEncryption>
<authentication>{authentication}</authentication>
<encryption>{encryption}</encryption>
<useOneX>false</useOneX>
</authEncryption>
<sharedKey>
<keyType>{key_type}</keyType>
<protected>false</protected>
<keyMaterial>{password}</keyMaterial>
</sharedKey>
</security>
</MSM>
</WLANProfile>
"""
connection_params = {
"connectionMode": "wlan_connection_mode_temporary_profile",
"profile": profile_string,
"ssid": None,
"bssidList": None,
"bssType": "dot11_BSS_type_infrastructure",
"flags": WLAN_CONNECTION_HIDDEN_NETWORK,
}
ctx = ConnectCallbackContext(interface.guid_string, 0, 0, 0)
notification_obj = ww.registerNotification(_wlan_connect_callback, context=ct.pointer(ctx))
try:
res = ww.connect(interface, connection_params)
except Exception as e:
ww.unregisterNotification(notification_obj)
raise WLANException("WlanConnect failed") from e
end_time = time.time() + timeout;
while time.time() < end_time:
time.sleep(0.5)
if ctx.end:
break
ww.unregisterNotification(notification_obj)
if ctx.end:
if ctx.fail:
raise WLANException(-2, "Connection failed")
else:
raise WLANException(-3, "Connection timed out")
return interface.guid_string
def wireless_disconnect(interface_guid):
handle = ww.WlanOpenHandle()
try:
ww.WlanDisconnect(handle, comtypes.GUID(interface_guid))
except Exception as e:
raise WLANException("WlanDisconnect failed") from e
finally:
ww.WlanCloseHandle(handle)
def main(*argv):
if argv:
try:
guid = argv[0]
print("Disconnecting wireless interface {:s} ...".format(guid))
wireless_disconnect(guid)
except:
traceback.print_exc()
else:
try:
print("Connecting to wireless network ...")
ssid = "DIGI_6e2a70"
pwd = "3ff091d5"
guid = wireless_connect(ssid, pwd)
print("Connected interface {:s}".format(guid))
except:
traceback.print_exc()
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
script00.bat:
setlocal enableextensions enabledelayedexpansion
set _EXE_PTYHON="e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe"
time <nul
ping www.google.com
%_EXE_PTYHON% code00.py
ping www.google.com
%_EXE_PTYHON% code00.py {0C58E048-BC0B-4D5F-A21F-FCD4E4B31806}
ping www.google.com
time <nul
Output:
[cfati@CFATI-5510-0:e:\Work\Dev\StackOverflow\q056721759]> sopr.bat
[prompt]> script00.bat
[prompt]> time 0<nul
The current time is: 1:45:08.31
Enter the new time:
[prompt]> ping www.google.com
Ping request could not find host www.google.com. Please check the name and try again.
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code00.py
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 064bit on win32
Connecting to wireless network ...
Connected interface {0C58E048-BC0B-4D5F-A21F-FCD4E4B31806}
Done.
[prompt]> ping www.google.com
Pinging www.google.com [2a00:1450:400d:809::2004] with 32 bytes of data:
Reply from 2a00:1450:400d:809::2004: time=11ms
Reply from 2a00:1450:400d:809::2004: time=12ms
Reply from 2a00:1450:400d:809::2004: time=12ms
Reply from 2a00:1450:400d:809::2004: time=19ms
Ping statistics for 2a00:1450:400d:809::2004:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 11ms, Maximum = 19ms, Average = 13ms
[prompt]> "e:\Work\Dev\VEnvs\py_pc064_03.07.06_test0\Scripts\python.exe" code00.py {0C58E048-BC0B-4D5F-A21F-FCD4E4B31806}
Python 3.7.6 (tags/v3.7.6:43364a7ae0, Dec 19 2019, 00:42:30) [MSC v.1916 64 bit (AMD64)] 064bit on win32
Disconnecting wireless interface {0C58E048-BC0B-4D5F-A21F-FCD4E4B31806} ...
Done.
[prompt]> ping www.google.com
Ping request could not find host www.google.com. Please check the name and try again.
[prompt]> time 0<nul
The current time is: 1:45:12.82
Enter the new time:
注释:
为了创建一个POC,我不得不添加一些代码(例如wireless_disconnect),这些代码并不一定与问题相关,但增加了复杂性。顺便说一句,代码比我最初预期的要复杂得多(这就是为什么我没费心去解释它——因为这会导致过度),但我看不到任何简化它的方法。
script00.bat(和time
正如我所指定的那样,这更像是一个POC,(我的和Win32Wifi的)代码存在一些限制。某些情况下(网络)可能需要进行(小)代码更改才能正常工作。
尽管连接到网络成功(并且有效),但在系统托盘中,网络状态仍显示为已断开连接(实际上在短暂的一秒钟内它会显示为已连接,但然后它会自动更改)。此外,系统托盘中的网络图标显示为已连接。我不确定这是我忘记以某种方式通知Win(虽然这没有太多意义),还是Win不喜欢“其他人”连接到无线网络。
最重要的一个:上述代码将无法直接使用,因为Win32Wifi存在缺陷。我发现了两个致命的(关键)错误,这对于这种情况来说是致命的,并且还有一堆其他较小的错误。我刚刚提交了kedos/win32wifi - Fixes(一些关键)和改进(已合并于200906年),但
PyPI上没有更新。
作为替代方案,您可以下载补丁并在本地应用更改。请参阅Run/Debug a Django application's UnitTests from the mouse right-click context menu in PyCharm Community Edition?(@CristiFati的答案)(Patching utrunner部分)以了解如何在Win上应用补丁(基本上,每行以一个“+”号开头的行都会进入,而每行以一个“-”号开头的行都会退出)。
winwifi.WinWiFi.connect('network_ssid', 'network_pwd')
时,它无法重新连接。但是,如果我只做winwifi.WinWiFi.connect('network_ssid')
-没有pwd- 它将重新连接到wifi。我有Python 3.8、Windows 10和PyCharm Community Edition 2020.2。 - xiaxio