Skip to content

🔰 Python脚本:如何一键登陆或开机自动登录公共区域的 WIFI?

🕒 Published at:

auto wifi script

一对情侣第一次来某酒店入住,男生给女友开了门,女友进来后,男生看到女友的电脑自动连接上了酒店的 wifi,男生脸上露出了不悦。

男生:你怎么知道这个 wifi 密码?

女友:我不知道,我的设备自动连接上了。

男生:那你之前来过这家酒店吗?

女友:没有啊,我第一次来。

男生:那你怎么知道密码?

女友:不知道,我的电脑自动连接上了。

男生:那你的电脑是不是被别人破解过?

女友:没有啊,我一向很小心的。

男生:那你怎么知道密码?

女友:我不知道,我就这样自动连接上了。

男生:那你是不是……

女友:对了,我以前在“艺述论”下载过一个自动登录 wifi 的小脚本。

Python脚本:如何一键登陆或开机自动登录公共区域的 WIFI?

我们都知道,wifi 有自动连接的功能,只要设备出现在 wifi 覆盖的区域之内,wifi 即会自动连接。这个自动登陆的机制在人数少的情况下完全没有问题,但在人多的公共场合,可能便会导致路由器因为连接负荷过大而产生信号资源浪费(每个路由器可供连接的设备都是有限的)。为此,在大型公共场合,例如校园、图书馆等,一般用户在自动无密码连接上 wifi 以后,还会被要求输入用户名密码之类,登录之后才可以开启真正的网络连接。同时呢,使用实名帐号登录,也是信息监控的必要。

对于个人来讲,例如学生,每次都输入帐号密码是十分麻烦的。有些手机在连接后可以记住帐号,单击一下就可以;有一些却不可以,每次都需要浪费几十秒钟手动输入。在电脑上,wifi 连接后,弹出的窗口往往还是一个没有地址栏,且不能使用开发者工具查看网络链接的祼窗口,想破解地址都不太容易。

那么,怎么实现一键登陆呢?

1,拿登录网关地址

第一步,我们需要先找到要登录的本地服务器地址。可以使用如下 bash 脚本,在登陆 wifi 前监听本机网络活动:

bash
sudo tcpdump -A -s 0 'port 80 or port 443'
sudo tcpdump -A -s 0 'port 80 or port 443'

简单解释下这条指令:

  • sudo:以超级用户身份运行命令。
  • tcpdump:网络流量捕获工具。
  • -A:捕获所有数据包,包括数据包头和数据包内容。
  • -s 0:捕获所有数据包,包括 IP 头和 TCP 头。
  • 'port 80 or port 443':捕获 TCP 端口为 80 或 443 的数据包。

tcpdump outputs

这个指令输出的信息量很大,但通过先拷贝出来再搜索的方式,很容易可以拿到一个类似于“http://192.168.2.253:8080/api/TZTSG/wifi-auth”这样的地址。我们猜测这个地址,便是公共WIFI的登陆地址。在连接外网之前可以访问的网络地址一定是一个内网地址,这样的地址一般都是以192.168或10.3这样的IP端开头的。

拿到这个地址以后,按说便可以将它保存到浏览器的收藏夹里,下次连接 wifi 的时候,单击一下就可以登录了。收藏的链接在浏览器内会自动记住用户名与密码,不会要求重复输入,这样已经很方便了。

但,我们是不是还可以更方便一些?

2,自动发送登录请求

第二步,我们谋划在本地发出一个网络请求。经过在开发者工具中查看网络请求的请求头,我们发现此类请求真是太简单了,是一个 GET 请求,用户名与密码直接拼接在了 URL 中,连加密都没有加密。

我们在本地创建一个脚本文件 login_wifi.py,主要代码如下所示:

python
import requests

# 定义常量
BASE_URL = "http://192.168.2.253:8080"
CODE = "001300095176"
PWD = "830918"

def connect_wifi():
  # 设置请求参数
  url = BASE_URL + "/api/tztsg/wifi-auth"
  params = {
      "code": CODE,
      "pwd": PWD,
  }

  # 设置防真请求信息
  headers = {
      "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
      "Referer": BASE_URL + "/wifiauth",
      "Dnt": "1",
      "Accept": "application/json, text/plain, */*",
      "Accept-Encoding": "gzip, deflate",
      "Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
      "Connection": "keep-alive",
      "Cookie": "_ga=GA1.1.1192614528.1695689014; username="+CODE+"; password="+PWD+"; rememberMe=true; _ga_GDWQY4XZV0=GS1.1.1695689014.1.1.1695689447.0.0.0",
  }

  # 发送请求
  response = requests.get(url, params=params, headers=headers)
  print(response)

  # 处理响应
  if response.status_code == 200:
      print("登录成功")
  else:
      print("登录失败")
import requests

# 定义常量
BASE_URL = "http://192.168.2.253:8080"
CODE = "001300095176"
PWD = "830918"

def connect_wifi():
  # 设置请求参数
  url = BASE_URL + "/api/tztsg/wifi-auth"
  params = {
      "code": CODE,
      "pwd": PWD,
  }

  # 设置防真请求信息
  headers = {
      "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36",
      "Referer": BASE_URL + "/wifiauth",
      "Dnt": "1",
      "Accept": "application/json, text/plain, */*",
      "Accept-Encoding": "gzip, deflate",
      "Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
      "Connection": "keep-alive",
      "Cookie": "_ga=GA1.1.1192614528.1695689014; username="+CODE+"; password="+PWD+"; rememberMe=true; _ga_GDWQY4XZV0=GS1.1.1695689014.1.1.1695689447.0.0.0",
  }

  # 发送请求
  response = requests.get(url, params=params, headers=headers)
  print(response)

  # 处理响应
  if response.status_code == 200:
      print("登录成功")
  else:
      print("登录失败")

这个代码很简单,不再介绍了。

为了防止服务器识破我们是代码自动提交的,我们在请求时还在 headers 里面添加了许多防真调用的信息。我估计这些信息大多数情况下都是不需要的,从前面的把帐号信息明文接写在 url 中便可以看出来,这样的登录系统毫无技术架构上的安全考虑,其开发者是不可能想起来要检验网络请求的来源信息的。

3,生成 exe 二进制程序

以非手动输入的方式一键发送登录请求,这个需求现在已经实现了。但有一个问题,py 脚本是明文的,帐号信息很容易暴露。

在第三步,我们准备将 py 脚本封装成一个 exe 二进制可执行程序文件,指令为:

bash
pip install pyinstaller
pyinstaller -F login_wifi.py
pip install pyinstaller
pyinstaller -F login_wifi.py

第一行安装 pyinstaller,第二行使用它将 py 脚本包装成独立的二进制程序。

在 macOS 系统上,这个指令会生成一个拥有黑色图标的二进制文件,以后登录网络直接单击这个文件就可以了,运行后效果如下所示。帐号密码及地址都封装在了 exe 文件里,这样也便于信息保密。

登录成功

小工具写到这里,基本上已经可以使用了。但是,还能不能进一优化呢?我们能不能自动监测电脑是否连接上了目标网络,并且自动给它发送登录请求呢?

整个登录环节信息都是足备的,并不需要人类参与,在理论上这完全是可行的。

4,实现自动登录

在第四步,我们开始实现自动登录。

先介绍一下类库 pywifi,这是一个可以监听网络变化的工具类库,我们可以用它监听风络变化,例如连接上了某个网络等。我们使用以下指令安装它:

bash
pip install pywifi
pip install pywifi

从终端的返回结果告诉我们安装成功了。但如果我们在 macOS 系统下使用它,可能会遇到问题,当我们在 py 代码中使用它时,可能遇到一个 NotImplementedError 这样的错误。

这个错误是不正常的,但出现这个错误却是正常的。pywifi 库的功能可能未在我们的操作系统上完全实现,它只能只是在特定的操作系统或环境中完全实现了。

pywifi 如果不可用,我们还有其它选择,我们可以尝试使用 networksetup 命令来获取当前的 WiFi 连接状态,如下所示是一个示例脚本。

python
import subprocess

target_ssid = 'TZTSG'

def check_wifi_connection(target_ssid):
    while True:
        result = subprocess.run(['networksetup', '-getairportnetwork', 'en0'], text=True, capture_output=True)
        if target_ssid in result.stdout:
            print(f'Connected to {target_ssid}')
            break
        else:
            print('Not connected')
        time.sleep(5)  # adjust polling interval as necessary
import subprocess

target_ssid = 'TZTSG'

def check_wifi_connection(target_ssid):
    while True:
        result = subprocess.run(['networksetup', '-getairportnetwork', 'en0'], text=True, capture_output=True)
        if target_ssid in result.stdout:
            print(f'Connected to {target_ssid}')
            break
        else:
            print('Not connected')
        time.sleep(5)  # adjust polling interval as necessary

类库 subprocess 在你的电脑上如果没有,可能需要提前安装。这段代码很简单,没有必要做进一步的介绍了,它的主要功能就是在一个 while 循环里,不断调用系统指令 networksetup,检查当前的网络状态,如果发现连接上了目标 wifi,则退出循环。

下面我们稍微修改一下前面的 login_wifi 脚本,将其与新的 check_wifi_connection 函数结合在一起。然后再次导出 exe 文件,并将其添加进系统的启动列表里,当系统启动时(或者我们手动执行时),自动检查网络连接,一旦发现是目标网络需要登录,则自动登录之。

成功运行之后,截图如下所示。自此,整个开机自动登录公共 wifi 的小程序就写好了。

自动监测并登录了

在公众号“艺述论”回复 10005,可以下载完整的 py 脚本,对帐号信息稍作修改即可为你所用。