前言
寝室安装了一个路由器, 但是不知道什么原因, 每天都会断开连接, 需要手动认证一下才可以, 为了避免不必要的麻烦, 写了这样一个小的python脚本来自动的重连
本文设计的操作有一定的上手难度, 不太适合对计算机完全不懂的同学使用, 如有需求, 可私聊
源码地址: https://github.com/Kingdo777/auto-connect-school-network.git, 或者见文末附录
源码解析
主函数非常的简单:
if __name__ == '__main__':
while True:
if pong():
time.sleep(5)
else:
login()
time.sleep(10)
每个5秒检查自己还能不能上网, 方式就是ping 8.8.8.8
, 这是很常见的方法.
如果不能上网, 那么就调用login()
函数来自动重连
我们的校园网认证的过程,本质上就是提交一个HTTP请求, 那我们的login()
函数, 其实就是实现了这个过程, 因此我们只需要知道,我们的网页端认证是怎么操作的即可,麻烦的是华科的校园网的代码设计的还是很复杂的,所以还是稍微的耗费了一点时间.
校园网认证流程
首先我们进入这个认证的页面, 按F12进入开发者模式

我们会在Source中看到两个重要的JS文件,当我们点击网页中的连接 Login
的时候就会调用这个函数.

这个函数会收集你的一系列信息,并最终调用:AuthInterFace.login

AuthInterFace
定义在 AuthInterFace.js
中.
其中init()
用于生成请求的url, login()
首先将传入的参数合并成content
,最后通过post方法发送请求

因此需要我们做的就是, 获取content
的内容, 然后我们就可以用python对指定的url发起post请求
获取content的方法也很简单, 只需要在如图位置打上断点, 然后点击网页中连接的按钮,当js执行到断点后,就可以复制content的值

使用
- git clone https://github.com/Kingdo777/auto-connect-school-network.git
- 我们将上一过程获取到的content信息存放到main.py的同目录下的名为
content
的文件中 - 然后就可以执行python脚本了
- 不过windows下需要安装npcap, 可以点击以下链接下载安装
https://nmap.org/npcap/dist/npcap-1.60.exe
后记
Notes
1) 在什么情况下, 需要重新获取Content?
如果切换了Wifi, 导致IP地址改变, 那么需要重新获取content的值.
这里很重要的一点需要了解, 只有在校园网内网IP发生改变的情况下才需要重新获取content的值, 而这个IP是你直接连接HUST_WIFI或者连接有线的时候需要的, 但是如果你在校园的基础之上加了一个自己买的路由器, 那么其实此路由器下所有的设备共用了路由器的校园网内网IP, 这个时候既是切换设备, 他们的content都是一样的.
2)在那些情况下可用?
此方法成功的前提之一是, 你已经连接了校园网, 有线或者无线! 如果没有连接, 那么程序有可能会崩溃退出!
此外, 如果你能成功打开浏览器,并跳出了认证了页面, 然后点击连接按钮连接成功, 那么此方法基本上都是成功的!
经过测试, 在以下情况下都可以重连:
- 在主动下线
- 被强制下线
- 被挤占下线
但是不知道你是否遇到过, 有时候认证的网页打不开! 这个时候程序会提示一条错误信息:
认证设备响应超时,请稍后再试!
我目前还没有找到解决此问题的方法!
官方脚本 mentohust
其实在Linux下有一个10年前的脚本文件, 名字叫mentohust, 其github地址是:HustLion/mentohust: 接续HustMoon开发的Mentohust,继续更新 (github.com)github.com/HustLion/mentohust
下载地址Long-term storage for Google Code Project Hosting.code.google.com/archive/p/mentohust/downloads
但是这个东西问题挺多的, 比如在WSL2中运行就会失败, 我怀疑她只能在直接连接校园网的设备上使用, 有兴趣大家自己玩玩吧:

更新一 简化ping操作
之前的ping操作过于臃肿, 当时是我随手百度的, 今天我又随手百度了一下, 看到了更好的方法:Python Function to test pingstackoverflow.com/questions/26468640/python-function-to-test-ping/39563638
其实就是直接调用os.system(“ping 8.8.8.8”), 然后根据返回结果来判断是否能通, 简化后的代码我放在了附录二.
我已经在Github上传了这个更新, 并且新方法不需要安装npcap软件!
更新二 异常处理和Ping优化
异常处理
python的requests.post方法, 并不是总是成功的, 比如此时你Wifi断开, 那么就会导致请求无法达到, 将会触发超时异常, 但是原来的代码中并没有添加异常的处理, 因此这将导致程序的退出, 因此添加了异常的情况的捕获.
此外, 在<后记->Notes>中提到可能会遇到“认证设备响应超时,请稍后再试!” , 对于这种情况我们需要延长睡眠的时间, 额外延长了 120秒
Ping优化
现有的方法, 只会ping一次8.8.8.8来验证是否可上网, 好处是速度很快, 缺点是容易误判, 也就是有可能此时网络拥堵, 依然有可能导致无法ping通, 但是其实是可以上网的, 因此我对ping操作进行了修改:

其中 202.114.0.242 是我们校园网的DNS服务器!以上方法可以最大程度的保证不会误判!
但是缺点是判断的流程会很长! 可以自己任意的修改怎么取舍!
(最新的代码已经上传的Github, 或者是附录三)
附录
附录一
import time
import json
from scapy.layers.inet import IP, ICMP
from scapy.packet import Raw
from scapy.sendrecv import sr1
import requests
def login():
url = 'http://192.168.50.3:8080/eportal/InterFace.do?method=login'
with open("content", "r") as f:
data = f.read()
header = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
}
response = requests.post(url, data, headers=header)
content = json.loads(response.text)
encoding = response.encoding
if content['result'] == 'fail':
print(content['message'].encode(encoding).decode('utf-8'))
else:
print("login at --> " + time.asctime(time.localtime(time.time())))
return
def pong():
ping_pkt = IP(dst="8.8.8.8") / ICMP() / b'welcome!'
ping_result = sr1(ping_pkt, timeout=2, verbose=False)
try:
if ping_result.getlayer(ICMP).fields['type'] == 0 \
and ping_result.getlayer(Raw).fields['load'] == b'welcome!':
return True
else:
return False
except Exception:
return False
if __name__ == '__main__':
while True:
if pong():
time.sleep(5)
else:
login()
time.sleep(10)
附录二
import json
import os
import sys
import time
import requests
def login():
url = 'http://192.168.50.3:8080/eportal/InterFace.do?method=login'
with open("content", "r") as f:
data = f.read()
header = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
}
response = requests.post(url, data, headers=header)
content = json.loads(response.text)
encoding = response.encoding
if content['result'] == 'fail':
print(content['message'].encode(encoding).decode('utf-8'))
else:
print("login at --> " + time.asctime(time.localtime(time.time())))
return
def pong():
if sys.platform.lower() == "win32":
response = os.system("ping -n 1 8.8.8.8 > ping.log")
else:
response = os.system("ping -c 1 8.8.8.8 > ping.log")
return response == 0
if __name__ == '__main__':
while True:
if pong():
time.sleep(5)
else:
login()
time.sleep(10)
附录三
import json
import os
import sys
import time
import requests
def login():
url = 'http://192.168.50.3:8080/eportal/InterFace.do?method=login'
with open("content", "r") as f:
data = f.read()
header = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
}
try:
response = requests.post(url, data, headers=header, timeout=10)
content = json.loads(response.text)
encoding = response.encoding
if content['result'] == 'fail':
msg = content['message'].encode(encoding).decode('utf-8')
print(msg)
if msg == "认证设备响应超时,请稍后再试!":
time.sleep(120)
else:
print("login at --> " + time.asctime(time.localtime(time.time())))
return
except Exception as info:
print("login 连接异常:" + str(info))
def ping(host, n):
cmd = "ping {} {} {} > ping.log".format(
"-n" if sys.platform.lower() == "win32" else "-c",
n,
host,
)
return 0 == os.system(cmd)
def pong():
return ping("202.114.0.242", 4) or ping("8.8.8.8", 4)
if __name__ == '__main__':
while True:
if pong():
time.sleep(5)
else:
login()
time.sleep(10)