简体   繁体   English

如何使用 Python 3 在 Windows 上连接到 WiFi 网络?

[英]How to connect to WiFi network on Windows using Python 3?

I am trying to write a script in Python 3 but all modules available today work on python 2 which will enable me to search for wireless networks and to connect to them.我正在尝试用 Python 3 编写脚本,但今天所有可用的模块都可以在 Python 2 上运行,这将使我能够搜索无线网络并连接到它们。 Is there any Python 3 library for this?是否有任何 Python 3 库?

The code I tried for python 2我为 python 2 尝试的代码

from wireless import Wireless
wireless = Wireless()
wireless.connect(ssid='ssid', password='password')

which is giving me an error这给了我一个错误

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

But this is not working since it is based on python 2. Is there any way to connect to a wifi using Python 3但这不起作用,因为它基于 python 2。有没有办法使用 Python 3 连接到 wifi

Is there a pressing need for this to be a library?是否迫切需要将其作为图书馆? It can be achieved easily without one (or if you prefer, save it as a module and import it).它可以在没有一个的情况下轻松实现(或者,如果您愿意,可以将其另存为模块并导入)。

If the wireless interface is wlan and the SSID and Profile name are the same (usually true) then just use如果无线接口是wlan并且 SSID 和配置文件名称相同(通常为 true),则只需使用

cmd = "netsh wlan connect name={0} ssid={0}".format(tt)
k = subprocess.run(cmd, capture_output=True, text=True).stdout

In the snippet above, tt is the name of the SSID you wish to connect to - it's a variable in my code because it connects to different SSIDs in turn.在上面的代码片段中, tt是您希望连接到的 SSID 的名称 - 它是我代码中的一个变量,因为它依次连接到不同的 SSID。

I know that using subprocess is something of a kludge, but the snippet above doesn't add any significant overhead.我知道使用subprocess有点麻烦,但上面的代码片段并没有增加任何显着的开销。

This is part of a script I wrote to 'harvest' data from my parents' solar inverters: the inverters have their own SSID, so the script has to connect to each in turn;这是我为从我父母的太阳能逆变器“收集”数据而编写的脚本的一部分:逆变器有自己的 SSID,因此脚本必须依次连接到每个逆变器; fetch real-time data using requests ;使用requests获取实时数据; store the data in a PostgreSQL db;将数据存储在 PostgreSQL 数据库中; and then reconnect to household wifi.然后重新连接到家庭wifi。

I know the devices also store historical data, however the data API was disabled by the manufacturer in ~2018 to drive owners towards their app (hence giving them user data to package and sell).我知道这些设备还存储历史数据,但是制造商在 2018 年左右禁用了数据 API,以推动所有者使用他们的应用程序(因此为他们提供用户数据以进行打包和销售)。

To connect wifi using python in windows, the better option is to use the winwifi module:在windows下使用python连接wifi,更好的选择是使用winwifi模块:

I recommend you to install plumbum before installing winwifi.我建议您在安装 winwifi 之前先安装 plumbum。 This is the link to download plumbum: https://pypi.org/project/plumbum/这是下载plumbum的链接: https : //pypi.org/project/plumbum/

After this install winwifi from here: https://pypi.org/project/winwifi/ It's better to install it in 32-bit python folder.从这里安装 winwifi 之后: https ://pypi.org/project/winwifi/ 最好将它安装在 32 位 python 文件夹中。

After installing you could check the module by the following code (This is to connect router which was connected to the device before) :安装好后可以通过如下代码查看模块(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')

On running this code on your IDLE, you could see that the wifi is connected to your device.在您的 IDLE 上运行此代码时,您可以看到 wifi 已连接到您的设备。 If you want to connect a new device you could use the code after adding profile:如果要连接新设备,可以在添加配置文件后使用代码:

import winwifi
winwifi.WinWiFi.addprofile('ssid_of_router')
winwifi.WinWiFi.connect('the_ssid_of_router', 'password')

You can disconnect the current Wifi using the command:您可以使用以下命令断开当前 Wifi:

import winwifi
winwifi.WinWiFi.disconnect()

There are many more commands on this module, try to explore them.这个模块还有更多的命令,尝试探索它们。 Just refer to the main.py file in winwifi folder for many more.有关更多信息,请参阅winwifi文件夹中的 main.py 文件。

Notes (about [PyPI]: wireless 0.3.2 ]):注释(关于[PyPI]:无线 0.3.2 ]):

  • Does not (yet) support Python 3 : as somewhere in the code it uses the cmp function (which is only available in Python 2 )(还)支持Python 3 :因为在代码中的某个地方它使用了cmp函数(仅在Python 2 中可用)
    • I wanted to submit a pull request (as the fix is trivial), but apparently on GitHub it was already fixed, yet the PyPI repository was not updated (since 2016)我想提交一个拉取请求(因为修复很简单),但显然在GitHub 上它已经修复了,但PyPI存储库没有更新(自 2016 年以来)
  • Does not work on Win (only Nix drivers are listed on the homepage - basically it only launches shell commands)不适用于Win (主页上仅列出Nix驱动程序 - 基本上它只启动shell命令)

As a consequence, I'd suggest looking for alternatives:因此,我建议寻找替代方案:

Alright, after a lot of browsing of:好吧,经过大量浏览:

, I was able to come up with something. ,我能够想出一些东西。

code00.py :代码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.")

script.bat :脚本.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 *** 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:

Notes :注意事项

  • In order to create a POC I had to add some code (eg wireless_disconnect ) not necessarily related to the question, which adds complexity.为了创建一个POC,我必须添加一些与问题不一定相关的代码(例如wireless_disconnect ),这增加了复杂性。
    BTW , the code is waaay more complex than I initially anticipated (that's why I didn't bother to explain it - as it would be an overkill), but I don't see any way of trimming it down顺便说一句,代码比我最初预期的要复杂(这就是为什么我没有费心解释它 - 因为这会矫枉过正),但我没有看到任何削减它的方法
  • script.bat (and time <nul ) are just to prove in console that the code is connecting / disconnecting from the wireless network (and that I'm not connecting from Win in parallel) script.bat (和time <nul )只是为了在控制台中证明代码正在连接/断开无线网络(并且我没有从Win并行连接)
    • I don't know where the " 0 " part from time 0<nul (in the output) comes from我不知道time 0<nul (在输出中)的“ 0 ”部分来自哪里
  • As I specified, this is more like a POC , there are some limitations in (my and Win32Wifi ) code.正如我所指出的,这更像是一个POC ,(我的和Win32Wifi )代码有一些限制。 Some scenarios (networks) might not work without (small) code changes如果没有(小)代码更改,某些场景(网络)可能无法工作
  • Although connection to the network succeeds (and works ), in the System Tray , the network status still appears as disconnected (actually for a fraction of a second it appears connected, but then it automatically changes).尽管连接到网络成功(并正常工作),但在系统托盘中,网络状态仍显示为已断开连接(实际上在几分之一秒内显示已连接,但随后会自动更改)。 Also, the System Tray network icon shows as Connected .此外,系统托盘网络图标显示为Connected I'm not sure whether this is on my side (I forgot to somehow notify Win - although this doesn't make much sense), or Win doesn't like "someone else" to connect to wireless networks我不确定这是否在我这边(我忘了以某种方式通知Win - 尽管这没有多大意义),或者Win不喜欢“其他人”连接到无线网络
  • THE MOST IMPORTANT ONE : The above code will not work OOTB , because Win32Wifi is buggy .最重要的一点:上面的代码不能在OOTB 中工作,因为Win32Wifi有问题 I found 2 bugs that are fatal (critical) for this scenario , and a bunch of other smaller ones.我发现了 2 个对于这种情况来说是致命的(关键的)错误,以及一些其他较小的错误。
    I've just submitted [GitHub]: kedos/win32wifi - Fixes (some critical) and improvements .我刚刚提交了[GitHub]:kedos/win32wifi - 修复(一些关键)和改进 Not sure what its outcome it's going to be (considering the inactivity period).不确定它会是什么结果(考虑到不活动期)。

    As an alternative, you could download the patch, and apply the changes locally.作为替代方案,您可以下载补丁,并在本地应用更改。 Check [SO]: Run/Debug a Django application's UnitTests from the mouse right click context menu in PyCharm Community Edition?检查[SO]:从 PyCharm 社区版中的鼠标右键单击上下文菜单运行/调试 Django 应用程序的单元测试? (@CristiFati's answer) ( Patching utrunner section) for how to apply patches on Win (basically, every line that starts with one "+" sign goes in, and every line that starts with one "-" sign goes out). (@CristiFati 的回答)Patching utrunner部分)关于如何在Win上应用补丁(基本上,以一个“+”号开头的每一行都进入,以一个“-”号开头的每一行都退出)。 I am using Cygwin , btw .我正在使用Cygwin顺便说一句

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 我如何使用 python 连接到 WIFI.network 3 - how can i connect to WIFI network using python 3 在尝试使用python连接到wifi网络时出现ConnectionError - Getting ConnectionError, while trying to connect to wifi network using python Python、linux:使用wifi Cell和Scheme,如何连接到网络? - Python, linux: Using wifi Cell and Scheme, how do I connect to a network? 使用python连接到wifi网络 - Connecting to a wifi network using python 如何使用python查找并连接所有可用的wifi信号? - How to find all and connect all available wifi signals using python? 如果您之前没有连接到 wifi,如何通过 linux 或 Windows 上的 python 连接到 wifi。 (输入:SSID、密码) - How to connect to wifi if you didnt connect to it before, by python on linux or Windows. (input: SSID, PASSWORD) 使用 Windows 身份验证在 Python 中使用 SQL Alchemy 连接到网络上的 MS SQL - Connect to MS SQL on a network with SQL Alchemy in Python using Windows Authentication 如何在 Python 3 中禁用 WIFI? (视窗) - How to disable WIFI in Python 3? (Windows) 简单的Python程序,可通过用户输入凭据连接到安全的wifi网络 - Simple Python program to connect to a secure wifi network with user input credentials 我尝试通过 python 上的一个脚本在 ubuntu 中连接网络 wifi - I try connect a network wifi in ubuntu through one script on python
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM