Skip to content

校园网络服务¤

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() 会尝试:

  1. 访问外部地址,判断当前是否被 Portal 劫持
  2. 解析跳转后的认证页 URL
  3. 提取 user_ip 与认证页基地址
  4. 尝试推断真正的 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 服务地址、用户 IP
  • AuthResult: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;通常不需要自己拼 URL
  • SelfServiceSystem.login() 依赖页面里隐藏的 checkcode 字段,若学校页面改版,优先检查这里
  • 不同园区的自助服务系统地址可能不同;如果登录失败,先确认地址是否正确