[英]How to connect to WiFi network on Windows using Python 3?
我正在嘗試用 Python 3 編寫腳本,但今天所有可用的模塊都可以在 Python 2 上運行,這將使我能夠搜索無線網絡並連接到它們。 是否有任何 Python 3 庫?
我為 python 2 嘗試的代碼
from wireless import Wireless
wireless = Wireless()
wireless.connect(ssid='ssid', password='password')
這給了我一個錯誤
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\Himanshu Poddar\AppData\Local\Programs\Python\Python36-32\lib\site-packages\wireless\Wireless.py", line 23, in __init__
self._driver_name = self._detectDriver()
File "C:\Users\Himanshu Poddar\AppData\Local\Programs\Python\Python36-32\lib\site-packages\wireless\Wireless.py", line 50, in _detectDriver
compare = self.vercmp(ver, "0.9.9.0")
File "C:\Users\Himanshu Poddar\AppData\Local\Programs\Python\Python36-32\lib\site-packages\wireless\Wireless.py", line 71, in vercmp
return cmp(normalize(actual), normalize(test))
NameError: name 'cmp' is not defined
但這不起作用,因為它基於 python 2。有沒有辦法使用 Python 3 連接到 wifi
是否迫切需要將其作為圖書館? 它可以在沒有一個的情況下輕松實現(或者,如果您願意,可以將其另存為模塊並導入)。
如果無線接口是wlan
並且 SSID 和配置文件名稱相同(通常為 true),則只需使用
cmd = "netsh wlan connect name={0} ssid={0}".format(tt)
k = subprocess.run(cmd, capture_output=True, text=True).stdout
在上面的代碼片段中, tt
是您希望連接到的 SSID 的名稱 - 它是我代碼中的一個變量,因為它依次連接到不同的 SSID。
我知道使用subprocess
有點麻煩,但上面的代碼片段並沒有增加任何顯着的開銷。
這是我為從我父母的太陽能逆變器“收集”數據而編寫的腳本的一部分:逆變器有自己的 SSID,因此腳本必須依次連接到每個逆變器; 使用requests
獲取實時數據; 將數據存儲在 PostgreSQL 數據庫中; 然后重新連接到家庭wifi。
我知道這些設備還存儲歷史數據,但是制造商在 2018 年左右禁用了數據 API,以推動所有者使用他們的應用程序(因此為他們提供用戶數據以進行打包和銷售)。
在windows下使用python連接wifi,更好的選擇是使用winwifi模塊:
我建議您在安裝 winwifi 之前先安裝 plumbum。 這是下載plumbum的鏈接: https : //pypi.org/project/plumbum/
從這里安裝 winwifi 之后: https ://pypi.org/project/winwifi/ 最好將它安裝在 32 位 python 文件夾中。
安裝好后可以通過如下代碼查看模塊(This is to connect router which was connected to the device before)
:
import winwifi
winwifi.WinWiFi.connect('the_exact_ssid_or_name_of_your_known_wifi_router')
在您的 IDLE 上運行此代碼時,您可以看到 wifi 已連接到您的設備。 如果要連接新設備,可以在添加配置文件后使用代碼:
import winwifi
winwifi.WinWiFi.addprofile('ssid_of_router')
winwifi.WinWiFi.connect('the_ssid_of_router', 'password')
您可以使用以下命令斷開當前 Wifi:
import winwifi
winwifi.WinWiFi.disconnect()
這個模塊還有更多的命令,嘗試探索它們。 有關更多信息,請參閱winwifi文件夾中的 main.py 文件。
注釋(關於[PyPI]:無線 0.3.2 ]):
因此,我建議尋找替代方案:
好吧,經過大量瀏覽:
,我能夠想出一些東西。
代碼00.py :
#!/usr/bin/env python3
import sys
import time
import ctypes
import comtypes
import traceback
from win32wifi import Win32Wifi as ww
ERROR_SUCCESS = 0
WLAN_CONNECTION_HIDDEN_NETWORK = 0x00000001
class WLANException(Exception): pass
class ConnectCallbackContext(ctypes.Structure):
_fields_ = [
("guid", ctypes.c_wchar_p),
("start", ctypes.c_byte),
("end", ctypes.c_byte),
("fail", ctypes.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, # secs
authentication="WPA2PSK", # "open",
encryption="AES", # "WEP",
key_type="passPhrase", # "networkKey",
interface_index=0, # Don't modify this (until PCs with more than 1 WLAN adapter arise :) )
):
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=ctypes.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): # Borrowed (and improved) this func from win32wifi.Win32Wifi, to avoid creting the interface when only its guid is required
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 = "Network SSID" # ssid and pwd here are (deliberately) dummy
pwd = "Network password"
guid = wireless_connect(ssid, pwd)
print("Connected interface {:s}".format(guid))
except:
traceback.print_exc()
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main(sys.argv[1:])
print("\nDone.")
腳本.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
輸出:
[cfati@CFATI-5510-0:e:\\Work\\Dev\\StackOverflow\\q056721759]> sopr.bat *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages *** [prompt]> script.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)] 64bit 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)] 64bit 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:
注意事項:
time <nul
)只是為了在控制台中證明代碼正在連接/斷開無線網絡(並且我沒有從Win並行連接)
time 0<nul
(在輸出中)的“ 0 ”部分來自哪里最重要的一點:上面的代碼不能在OOTB 中工作,因為Win32Wifi有問題。 我發現了 2 個對於這種情況來說是致命的(關鍵的)錯誤,以及一些其他較小的錯誤。
我剛剛提交了[GitHub]:kedos/win32wifi - 修復(一些關鍵)和改進。 不確定它會是什么結果(考慮到不活動期)。
作為替代方案,您可以下載補丁,並在本地應用更改。 檢查[SO]:從 PyCharm 社區版中的鼠標右鍵單擊上下文菜單運行/調試 Django 應用程序的單元測試? (@CristiFati 的回答) ( Patching utrunner部分)關於如何在Win上應用補丁(基本上,以一個“+”號開頭的每一行都進入,以一個“-”號開頭的每一行都退出)。 我正在使用Cygwin ,順便說一句。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.