使用python实现drcom服务的接口

根据校园网登录界面,F12解析请求,使用python3实现3个功能:

  • 检查登录状态

  • 登录

  • 注销

web_login.py

import requests
import json
import re
import sys
import logging
from urllib.parse import quote
import argparse

# 配置日志
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")

# 常量定义
BASE_URL = "http://*.*.*.*"认证的网址。
AUTH = ("user", "passwd")  # 路由器认证信息

# 获取 WAN IP 地址,我这里使用路由器登录的,所以需要获取路由器的wan口ip,如果直接使用电脑则不需要用这个获取。
def get_wan_ip():
    url = "http://内网路由器/status_wanlink.asp"
    try:
        response = requests.get(url, auth=AUTH, timeout=10)
        response.raise_for_status()
        content = response.text
        match = re.search(r"wanlink_ip4_wan\(\)\s*\{\s*return\s*'([\d\.]+)'", content)
        return match.group(1) if match else "0.0.0.0"
    except requests.exceptions.RequestException as e:
        logging.error(f'获取 WAN IP 地址失败: {e}')
        return "0.0.0.0"

# 执行请求并解析返回的 JSON 数据
def web_analyze(url):
    try:
        response = requests.get(url, timeout=10)
        response.raise_for_status()
        text = response.text
        if '(' in text and ')' in text:
            return json.loads(text[text.index('(') + 1:text.rindex(')')])
        return json.loads(text)
    except (requests.exceptions.RequestException, json.JSONDecodeError) as e:
        logging.error(f'请求或解析失败: {e}')
        return None

# 处理 JSON 数据
def handle_json_data(json_data):
    if not json_data:
        return -1  # 如果数据为空,返回 -1

    result = json_data.get("result", -1)
    msg = json_data.get("msg", "未知消息")

    if result == 1:
        logging.info(f'返回代码: {result}, 消息: {msg}')
        logging.info('操作成功!')
    elif result == 0:
        if "已经在线" in msg:
            logging.warning(f'返回代码: {result}, 消息: {msg}')
            logging.warning('已经在线,请勿重复登录!')
        else:
            logging.error(f'操作失败,返回数据: {json_data}')
    else:
        logging.error(f'未知返回代码: {result}, 消息: {msg}')
        logging.error('操作状态未知!')

    return result  # 返回 result 值

# 解析命令行参数
def parse_args():
    parser = argparse.ArgumentParser(description="处理登录、注销和检查状态的脚本")
    parser.add_argument("action", choices=["check", "logout", "wanip", "login"], help="操作类型")
    parser.add_argument("username", nargs="?", help="用户名(仅用于登录操作)")
    parser.add_argument("password", nargs="?", help="密码(仅用于登录操作)")
    return parser.parse_args()

if __name__ == '__main__':
    args = parse_args()
    if args.action == "login" and (not args.username or not args.password):
        logging.error("Error: 登录操作需要用户名和密码")
        sys.exit(1)

    result = -1  # 默认返回 -1

    if args.action == "check":
        url = f'{BASE_URL}/drcom/chkstatus?callback=dr1002&jsVersion=4.1&v=7123&lang=zh'
        json_data = web_analyze(url)
        if json_data:
            result = json_data.get("result", -1)
            logging.info(f'登录状态: {result}')
            logging.info(f'IP 地址: {json_data.get("v46ip", "未知IP")}')
    elif args.action == "logout":
        url = f'{BASE_URL}/drcom/logout?callback=dr1006&jsVersion=4.1&v=1949&lang=zh'
        json_data = web_analyze(url)
        if json_data:
            result = json_data.get("result", -1)
            if result == 0:
                logging.error(f'登录出错:{json_data.get("msga", "未知错误")}')
            else:
                logging.info(f'注销状态: {result}')
                logging.info(f'IP 地址: {json_data.get("ss5", "未知IP")}')
    elif args.action == "wanip":
        wan_ip = get_wan_ip()
        logging.info(f'WAN IP 地址: {wan_ip}')
        result = 1 if wan_ip != "0.0.0.0" else -1  # 如果获取到 IP,返回 1;否则返回 -1
    elif args.action == "login":
        wan_ip = get_wan_ip()
        url = (
            f'{BASE_URL}:801/eportal/portal/login?callback=dr1003&login_method=1&'
            f'user_account={quote(args.username)}&user_password={quote(args.password)}&'
            f'wlan_user_ip={wan_ip}&wlan_user_ipv6=&wlan_user_mac=000000000000&'
            f'wlan_ac_ip=&wlan_ac_name=&jsVersion=4.1.3&terminal_type=1&lang=zh-cn&v=4639&lang=zh'
        ) #F12 查看的post链接,直接组合
        json_data = web_analyze(url)
        result = handle_json_data(json_data)  # 调用 handle_json_data 处理并返回 result
    else:
        logging.error("Error: 无效的操作类型")
        sys.exit(1)

    print(result)  # 统一输出 result 值

上述py可以实现三个效果(我已经登录了就没有展示了)

> python .\web.py login xxxxxxxxx xxxxxxxxx	# 使用账号密码登录

2025-01-08 12:26:59,384 - WARNING - 返回代码: 0, 消息: IP: 10.252.*.* 已经在线!
2025-01-08 12:26:59,385 - WARNING - 已经在线,请勿重复登录!
0

PS C:\Users\guo\Desktop\proxy> python web.py check                      
2025-01-08 12:26:26,853 - INFO - 登录状态: 1
2025-01-08 12:26:26,853 - INFO - IP 地址: 10.252.4.235
1

> python .\web.py logout	# 注销

编写PowerShell脚本执行自动登录

# 配置路径和参数
$web_path = "D:\login\web.py"  # 替换为 Python 脚本的路径
$username = "xxxxxxxxx"   # 校园网的账号
$password = "xxxxxxxxx"  # 校园网的密码

# 主循环
while ($true) {
    try {
        # 调用 Python 脚本检查登录状态
        $result = & python $web_path check
        Write-Host "检查结果: $result"

        # 解析 Python 脚本的输出
        if ($result -match "0") {
            Write-Host "未登录,尝试登录..."
            $login_result = & python $web_path login $username $password
            Write-Host "登录结果: $login_result"
        } elseif ($result -match "1") {
            Write-Host "已登录,无需操作"
        } else {
            Write-Host "未知状态,跳过"
        }
    } catch {
        Write-Host "发生错误: $_"
        Pause
    }

    # 等待 1800 秒后再次检查
    Start-Sleep -Seconds 1800
}

添加开机启动,实现开机自动启动。如果是linux系统也是同理。

为了防止脚本意外退出,我还设置了一个守护脚本(windows添加每小时运行一次的计划任务即可),当然也可以将上面脚本设置成计划任务。

# 配置路径和参数
$script_name = "auto_login_web.ps1"  # 主脚本的名称
$ping_target = "www.baidu.com"  # 外网检测的目标 IP 或域名
$ping_timeout = 1000  # Ping 超时时间(毫秒)
$max_retries = 3  # 最大重试次数

# 检测外网连通性,如果网络是好的就没必要进行启动任务。
function Test-InternetConnection {
    $retry_count = 0
    while ($retry_count -lt $max_retries) {
        try {
            # 使用 ping.exe 检测
            $ping_result = ping $ping_target -n 1 -w $ping_timeout
            # 输出调试信息
            Write-Host "Ping 尝试 $($retry_count + 1): $ping_result"
            # 如果结果包含 "TTL=",说明 Ping 成功
            if ($ping_result -match "TTL=") {
                return $true
            }
        } catch {
            # 输出错误信息
            Write-Host "Ping 尝试 $($retry_count + 1) 失败: $_"
        }
        # 增加重试次数
        $retry_count++
        # 等待 1 秒后重试
        Start-Sleep -Seconds 1
    }
    # 如果 3 次都失败,返回 false
    return $false
}

# 主逻辑
if (-not (Test-InternetConnection)) {
    Write-Host "外网不通,正在检查主脚本是否运行..."

    # 检查主脚本是否在运行
    $process = Get-Process -Name powershell -ErrorAction SilentlyContinue | Where-Object {
        $_.MainWindowTitle -match $script_name
    }

    if (-not $process) {
        Write-Host "主脚本未运行,正在启动..."
        Start-Process powershell -ArgumentList "-File `"$PSScriptRoot\$script_name`""
    } else {
        Write-Host "主脚本正在运行"
    }
} else {
    Write-Host "外网正常,跳过检测"
}

使用路由器脚本(我的是Padavan)实现drcom登录

#!/bin/sh

# 配置区(使用前必须修改!!!)
BASE_URL="http://your_auth_server"  # 认证服务器地址
USERNAME="your_username"            # 宽带账号
PASSWORD="your_password"            # 宽带密码
WAN_IF="eth3"                       # WAN口网络接口

# 日志记录
log() {
    echo "[$(date '+%m-%d %H:%M:%S')] $1"
}

# 获取WAN口IP
get_wan_ip() {
    ifconfig $WAN_IF | awk -F'[ :]+' '/inet addr/ {print $4}'
}

# 简易JSON解析
parse_json() {
    echo "$1" | sed -n 's/.*"'"$2"'":\([^,}]*\).*/\1/p' | tr -d '"'
}

# 状态检测
check_login() {
    response=$(curl -s "$BASE_URL/drcom/chkstatus?callback=dr1002&jsVersion=4.1&v=7123&lang=zh" 2>&1)
    
    # 检测curl是否超时
    case $response in
        *"timed out"*) 
            log "网络连接超时"
            return 2
            ;;
        *"Could not resolve host"*)
            log "DNS解析失败"
            return 3
            ;;
    esac
    
    json_data=$(echo "$response" | sed 's/^dr[0-9]*(//;s/)$//')
    result=$(parse_json "$json_data" "result")
    
    [ "$result" = "1" ] && return 0 || return 1
}

# 执行登录
do_login() {
    wan_ip=$(get_wan_ip)
    [ -z "$wan_ip" ] && { log "获取WAN口IP失败"; return 1; }
    
    login_url="$BASE_URL:801/eportal/portal/login?callback=dr1003&login_method=1&user_account=$USERNAME&user_password=$PASSWORD&wlan_user_ip=$wan_ip&wlan_user_mac=000000000000&jsVersion=4.1.3&lang=zh"
    
    response=$(curl -s "$login_url" 2>&1)
    json_data=$(echo "$response" | sed 's/^dr[0-9]*(//;s/)$//')
    
    case $(parse_json "$json_data" "result") in
        "1")
            log "登录成功 ➜ IP: $wan_ip"
            return 0
            ;;
        "0")
            msg=$(parse_json "$json_data" "msg")
            log "登录失败:${msg:-未知错误}"
            return 1
            ;;
        *)
            log "服务器返回异常:$json_data"
            return 1
            ;;
    esac
}

# 主程序
main() {
    # 优先获取WAN口IP
    wan_ip=$(get_wan_ip)
    [ -z "$wan_ip" ] && { log "获取WAN口IP失败,请检查网线连接"; exit 1; }
    log "当前WAN口IP ➜ $wan_ip"
    
    check_login
    case $? in
        0)
            log "当前已在线 ✔"
            ;;
        1)
            log "检测到未登录,开始认证..."
            do_login || exit 1
            ;;
        2)
            log "网络异常,尝试强制登录..."
            do_login
            ;;
        *)
            log "系统错误,请检查网络配置"
            exit 1
            ;;
    esac
}

# 执行主程序
main

文章参考了https://blog.csdn.net/DLW__/article/details/131642450