校园网络服务¤
zzupy.web.network 提供三部分能力:
discover_portal_info():自动探测当前网络的 Portal 参数EPortalClient:执行 Portal 认证SelfServiceSystem:登录校园网自助服务系统并管理在线设备
Portal 认证¤
推荐流程:先自动发现,再认证¤
自动发现 Portal 信息
from zzupy.web import EPortalClient, discover_portal_info
portal = discover_portal_info()
with EPortalClient(portal.portal_server_url, bind_address=portal.user_ip) as client:
result = client.auth("your_account", "your_password")
print(result.success, result.message)
discover_portal_info() 会尝试:
- 访问外部地址,判断当前是否被 Portal 劫持
- 解析跳转后的认证页 URL
- 提取
user_ip与认证页基地址 - 尝试推断真正的 Portal 服务端地址
调用前提
这个探测流程需要你当前处于校园网认证环境中。如果已经完成认证,它会抛出 NetworkError。
手动指定 Portal 地址¤
如果你已经知道 Portal 服务地址,也可以直接创建客户端:
直接认证
from zzupy.web import EPortalClient
with EPortalClient("http://172.16.2.9:801") as client:
result = client.auth("your_account", "your_password")
print(result.message)
EPortalClient 参数说明¤
bind_address¤
默认会自动取本机 IP,也可以手动指定:
with EPortalClient("http://172.16.2.9:801", bind_address="192.168.1.100") as client:
result = client.auth("your_account", "your_password")
force_bind¤
在路由器或旁路网关环境中,本机可能并没有 portal.user_ip 对应的地址。此时可以启用 force_bind=True,让客户端即使无法真正绑定该 IP,也把它写入认证参数:
portal = discover_portal_info()
with EPortalClient(
portal.portal_server_url,
bind_address=portal.user_ip,
force_bind=True,
) as client:
result = client.auth("your_account", "your_password")
isp_suffix¤
auth() 支持直接追加运营商后缀:
融合宽带示例
result = client.auth("your_account", "your_password", isp_suffix="@cmcc")
常见值:
@cmcc@unicom@telecom
encrypt¤
auth(..., encrypt=True) 会启用 Portal 参数加密模式,对应底层的 portal_auth() 加密实现。
result = client.auth("your_account", "your_password", encrypt=True)
实际情况
当前大多数校园网 Portal 场景下并不需要启用该选项。
Portal 返回结果¤
EPortalClient.auth() 返回 zzupy.model.network.AuthResult:
result:结果码message:服务端消息(由msg字段映射而来)ret_code:附加状态码,可能为空success:当result == 1时为True
result = client.auth("your_account", "your_password")
if result.success:
print("认证成功")
else:
print(result.message)
自助服务系统¤
SelfServiceSystem 用于访问学校的校园网自助服务页面。不同园区的地址可能不同,常见形式类似 http://10.2.7.16:8080。
登录并查看在线设备¤
查询在线设备
from zzupy.web import SelfServiceSystem
with SelfServiceSystem("http://10.2.7.16:8080") as system:
system.login("your_account", "your_password")
devices = system.get_online_devices()
for device in devices:
print(device.ip, device.mac, device.loginTime)
踢设备下线¤
踢掉一台设备
with SelfServiceSystem("http://10.2.7.16:8080") as system:
system.login("your_account", "your_password")
devices = system.get_online_devices()
if devices:
system.kick_device(devices[0].sessionId)
数据模型¤
常用模型位于 zzupy.model.network:
PortalInfo:认证页地址、Portal 服务地址、用户 IPAuthResult:Portal 认证结果OnlineDevice:自助服务系统中的在线设备信息
异步版本¤
异步接口位于 zzupy.aio.web.network:
异步 Portal 认证
import asyncio
from zzupy.aio.web import EPortalClient, SelfServiceSystem, discover_portal_info
async def main():
portal = await discover_portal_info()
async with EPortalClient(portal.portal_server_url, bind_address=portal.user_ip) as client:
result = await client.auth("your_account", "your_password")
print(result.message)
async with SelfServiceSystem("http://10.2.7.16:8080") as system:
await system.login("your_account", "your_password")
devices = await system.get_online_devices()
print(len(devices))
asyncio.run(main())
异常¤
常见异常:
ZZUError:所有项目异常的基类,带context可用于统一日志处理NetworkError:网络请求失败,或当前网络不在预期认证状态ParsingError:HTML / JSON / JSONP 结构变化LoginError:自助服务系统登录失败NotLoggedInError:未登录却调用需要登录的方法OperationError:踢设备等操作收到异常状态码
注意事项¤
discover_portal_info()返回的是PortalInfo;通常不需要自己拼 URLSelfServiceSystem.login()依赖页面里隐藏的checkcode字段,若学校页面改版,优先检查这里- 不同园区的自助服务系统地址可能不同;如果登录失败,先确认地址是否正确