python实现清华大学联网助手

最终目标希望完成如下几个功能:

  • (1)登录校园网
  • (2)登出校园网
  • (3)查询当前网络状态
  • (4)查询流量、帐户余额、当前用户组等基本信息
  • (5)查询本账号当前在线IP信息
  • (6)查询每日流量使用明细,并生成直方图

使用方法

使用前请到同级目录下USERNAME_PASSWORD.txt文件中修改你的校园网账号和密码。
可将tunet.py设置为外部命令,参数如下:
-h, --help : 显示帮助
-v, --version: 显示当前清华大学联网助手版本号
-u : 输入用户名
-p : 输入密码
-a : 稍后输入用户名和密码,可以登录其他校园网帐户
-i, --login : 联网操作(当不带任何其他操作时,默认进行联网操作)
-o, --logout : 断网操作
-c, --check : 检查当前网络状态
-q, --query : 查询流量、帐户余额、当前用户组等基本信息,查询本账号当前在线IP信息,查询每日流量使用明细,并生成直方图,查询结果保存在USER_DETAIL_INFOMATION.LOG文件下

说明

(1)USER_DETAIL_INFOMATION.LOG文件保存最近一次综合查询结果
(2)USERNAME_PASSWORD.txt文件保存用户的账号和密码

版本v1.2更新内容

(1)增加了账户和密码的文件管理
(2)性能调整
(3)当不带任何参数时,默认连接校园网,简化输入

3 版本v1.1更新内容:

(1)增加了综合查询功能:查询流量、帐户余额、当前用户组等基本信息,查询本账号当前在线IP信息,查询每日流量使用明细,并生成直方图,查询结果保存在USER_DETAIL_INFOMATION.LOG文件中

版本v1.0更新内容:

(1)提供基本的联网、断网和检查当前网络状态的操作

QUERY

import sys, time, os
import urllib.request, hashlib, http.cookiejar
import codecs, re

query_login_url  = 'https://usereg.tsinghua.edu.cn/do.php'
user_info_url    = 'https://usereg.tsinghua.edu.cn/user_info.php'
online_state_url = 'https://usereg.tsinghua.edu.cn/online_user_ipv4.php'
query_logout_url = 'https://usereg.tsinghua.edu.cn/do.php'

info_header = [ '#' * 89,
                '#\t\t\t\tUser Flux Detail Infomation\t\t\t\t#',
                '#' * 89]

#########################################################
#                   File I/O Modules                    #
#########################################################

def create_path(relative_path):
    base_path = os.path.abspath(os.path.dirname(sys.argv[0]))
    return os.path.join(base_path, relative_path)

def write_inline(file_handler, contents):
    for line in contents:
        file_handler.write(line + '\r\n')

def save_query(contents):
    relative_path = 'USER_DETAIL_INFOMATION.LOG'
    file_handler = open(create_path(relative_path), 'w')
    write_inline(file_handler, info_header)
    file_handler.write('\t\t\t\tDatetime: ' + time.strftime('%Y-%m-%d %H:%M:%S') + '\r\n' + '-' * 89 + '\r\n')
    write_inline(file_handler, contents)
    file_handler.write('\r\n')
    file_handler.close()

#########################################################
#                   Connection Modules                  #
#########################################################

def create_opener():
    cookie = http.cookiejar.CookieJar()
    cookie_proc = urllib.request.HTTPCookieProcessor(cookie)
    return urllib.request.build_opener(cookie_proc)

def response_login(login_data):
    request_url = urllib.request.Request(query_login_url, login_data.encode())
    response_url = urllib.request.urlopen(request_url)
    return response_url.read().decode()

#########################################################
#               Main Login/Logout Modules               #
#########################################################

def query_login(username, password):
    hashcd_md5 = hashlib.md5()
    hashcd_md5.update(password.encode())
    tr_password = hashcd_md5.hexdigest()
    login_data = 'user_login_name=' + username + '&user_password=' + tr_password + '&action=login'
    urllib.request.install_opener(create_opener())
    answer = response_login(login_data)
    if answer == 'ok':
        return True
    else:
        return False

def query_logout():
    logout_data = 'action=logout'
    request_url = urllib.request.Request(query_logout_url, logout_data.encode())
    response_url = urllib.request.urlopen(request_url)
    print ('Your flux details and other infomations are saved in USER_DETAIL_INFOMATION.LOG under the SAME directory')

#########################################################
#               Data Post-Process Modules               #
#########################################################

def post_process(info):
    end_time = time.strftime('%Y-%m-%d')
    start_time = end_time[:8:] + '01'
    flux_detail_url = 'https://usereg.tsinghua.edu.cn/user_detail_list.php?action=balance2&user_login_name=&user_real_name=&desc=&order=&start_time=' + start_time + '&end_time=' + end_time + '&user_ip=&user_mac=&nas_ip=&nas_port=&is_ipv6=0&page=1&offset=200'  

    response_usr = urllib.request.urlopen(user_info_url)
    response_state = urllib.request.urlopen(online_state_url)
    response_details = urllib.request.urlopen(flux_detail_url)

    info = flux_account_query(info, response_usr)
    info = online_state_query(info, response_state)
    info = flux_detail_query(info, response_details)
    
    return info

#########################################################
#               Integrated Query Modules                #
#########################################################

flux_account_keys = ('用户名', '用户组', '姓名', '证件号', '当前计费组', '使用时长(IPV4)', '使用流量(IPV4)',
                     '使用时长(IPV6)', '使用流量(IPV6)', '帐户余额')
online_state_keys = ()
flux_detail_keys  = ()

#Auxiliary Function
def turn_key(key):
    if key[-5:-1] == 'byte':
        flux, unit = key.split('(')
        flux = float(flux) / 1024 / 1024
        new_key = '-->' + str(int(flux)) + '(MB)'
        key += new_key
    return key


def get_days(year, month):
    month_length = (31,28,31,30,31,30,31,31,30,31,30,31)
    month_length_leap = (31,29,31,30,31,30,31,31,30,31,30,31)
    if year % 400 == 0 or year % 100 != 0 and year % 4 == 0:
        return month_length_leap[month-1]
    else:
        return month_length[month-1]

def solve_flux(flux):
    unit = flux[-1]
    val = float(flux[:len(flux)-1:])

    if unit == 'B':
        val /= 1024 * 1024
    elif unit == 'K':
        val /= 1024
    elif unit == 'G':
        val *= 1024

    return int(val)

def trans_content(response):
    raw = response.read().decode('gb2312')
    raw = re.sub('<[^>]+>|&nbsp;|[\n\t]+|-->',' ',raw)
    raw = re.sub(' +', ' ', raw)
    return raw

def push_front(figure, line):
    tf = []
    tf.append(line)
    return tf + figure

def display_fluxAccount_onlineState(info):
    print()
    for line in info:
        if line[0] != '-':
            print(line)
        else:
            print()

def display_flux_detail(fluxin, year, month, day):
    maxflux = 0
    divide = 10
    figure = []
    for flux in fluxin:
        if flux > maxflux:
            maxflux = flux

    top = str(int(maxflux)) + 'MB|'
    length = len(top)
    mid = str(int(maxflux / 2)) + 'MB|'
    mid = ' ' * (length - len(mid)) + mid
    bottom = '0MB|'
    bottom = ' ' * (length - len(bottom)) + bottom
    unit = maxflux / divide

    for i in range(day):
        fluxin[i] = int(fluxin[i] / unit)

    for i in range(divide):
        line = ''
        if i == divide - 1:
            line = top
        elif i == int((divide - 1) / 2):
            line = mid
        elif i == 0:
            line = bottom
        else:
            line = ' ' * (length - 1) + '|'
        for j in range(day):
            if fluxin[j] > 0:
                line += '**'
                fluxin[j] -= 1
            else:
                line += '  '

        figure = push_front(figure, line)

    figure = push_front(figure, '**每日流量使用统计列表**')
    figure.append(' ' * length + '--' * day)
    date_front = str(year) + '-' + str(month) +'-' + '1'
    date_rear  = str(year) + '-' + str(month) +'-' + str(day)
    date_mid   = str(year) + '-' + str(month) +'-' + '15'
    figure.append(' %s\t\t\t%s\t\t\t%s' %(date_front, date_mid, date_rear))

    for line in figure:
        print(line)

    print()

#Integrated Query
def flux_account_query(info, response):
    info.append('**用户基本信息**')
    done = trans_content(response)
    match = re.search('用户名.*?(元) ', done)
    done = match.group()
    tlist = done.split(' ')
    line = ''

    for key in tlist:
        if line != '':
            key = turn_key(key)
            line = line + '\t: ' + key
            info.append(line)
            line = ''
        elif key in flux_account_keys:
            line = key

    info.append('-' * 89)
    return info

def online_state_query(info, response):
    info.append('**用户在线状态**')
    
    done = trans_content(response)
    match = re.search('\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.*\d{2}:\d{2}', done)

    if match == None:
        info.append('当前没有任何IP在线')
    else:
        info.append('在线IP地址\t登陆日期\t登陆时间')
        done = match.group()
        tlist = done.split(' ')
        line = ''
        count = 0

        for key in tlist:
            if count == 0:
                if re.search('\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,3}', key) != None:
                    line = key
                    count += 1
            elif count == 1:
                if re.search('\d{4}-\d{2}-\d{2}', key) != None:
                    line += '\t' + key
                    count += 1
            elif count == 2:
                if re.search('\d{2}:\d{2}:\d{2}', key) != None:
                    line += '\t' + key
                    info.append(line)
                    line = ''
                    count = 0

    info.append('-' * 89)
    display_fluxAccount_onlineState(info);
    return info

def flux_detail_query(info, response):
    info.append('**每日流量使用统计列表**')
    info.append('登出日期\t入流量\t出流量')
    done = trans_content(response)
    year, month = time.strftime('%Y %m').split(' ')
    days = get_days(int(year), int(month))
    tlist = done.split(' ')

    fluxin_perday = [0 for i in range(days)]
    fluxout_perday = [0 for i in range(days)]
    offline_date = True
    count = 0

    for key in tlist:
        if re.search('\d{4}-\d{2}-\d{2}', key) and offline_date:
            offline_date = False
        elif re.search('\d{4}-\d{2}-\d{2}', key) and not offline_date:
            offline_date = True
            year, month, day = key.split('-')
            iday = int(day)
        elif re.search('\d+[.]\d*[BKMG]', key) and count == 0:
            fluxin_perday[iday-1] += solve_flux(key)
            count += 1
        elif re.search('\d+[.]\d*[BKMG]', key) and count == 1:
            fluxout_perday[iday-1] += solve_flux(key)
            count += 1
        elif re.search('\d+[.]\d*[BKMG]', key) and count == 2:
            count = 0
    
    for i in range(days):
        if i + 1 < 10:
            d = '0' + str(i + 1)
        else:
            d = str(i + 1)
        info.append('%s\t%s\t%s' %(time.strftime('%Y-%m-') + d, str(fluxin_perday[i]) + 'MB', str(fluxout_perday[i]) + 'MB'))

    display_flux_detail(fluxin_perday, int(year), int(month), days)
    return info

#########################################################
#                       Main Part                       #
#########################################################

def tunet_query(username, password):
    print('FETCHING DATA FROM http://usereg.tsinghua.edu.cn, PLEASE WAIT FOR A MOMENT...')
    is_login = query_login(username, password)
    if is_login:
        info = []
        info = post_process(info)
        save_query(info)
        query_logout()
    else:
        print ('CAN\'T CAPTURE YOUR FLUX DATA, PLEASE TRY AGAIN LATER')

def pytunet_query():
    username = 'hhy14'
    password = '123456'
    tunet_query(username, password)

if __name__ == '__main__':
    pytunet_query()

CONNECT

import time
import urllib.request, hashlib
import codecs

login_url  = 'http://net.tsinghua.edu.cn/cgi-bin/do_login'
logout_url = 'http://net.tsinghua.edu.cn/cgi-bin/do_logout'
check_url  = 'http://net.tsinghua.edu.cn/cgi-bin/do_login'
query_url  = 'https://usereg.tsinghua.edu.cn/login.php'

times_cnt = {1: 'FIRST', 2: 'SECOND', 3: 'THIRD', 4: 'FORTH', 5: 'FIFTH'}
ret_type  = {'logout_ok'       : 'LOGOUT SUCCESS',
            'not_online_error' : 'NOT ONLINE',
            'ip_exist_error'   : 'IP ALREADY EXISTS',
            'user_tab_error'   : 'THE CERTIFICATION PROGRAM WAS NOT STARTED',
            'username_error'   : 'WRONG USERNAME',
            'user_group_error' : 'ACCOUNT INFOMATION INCORRECT',
            'password_error'   : 'WRONG PASSWORD',
            'status_error'     : 'ACCOUNT OVERDUE, PLEASE RECHARGE',
            'available_error'  : 'ACCOUNT HAS BEEN SUSPENDED',
            'delete_error'     : 'ACCOUNT HAS BEEN DELETED',
            'usernum_error'    : 'USERS NUMBER LIMITED',
            'online_num_error' : 'USERS NUMBER LIMITED',
            'mode_error'       : 'DISABLE WEB REGISTRY',
            'time_policy_error': 'CURRENT TIME IS NOT ALLOWED TO CONNECT',
            'flux_error'       : 'FLUX OVER',
            'ip_error'         : 'IP NOT VALID',
            'mac_error'        : 'MAC NOT VALID',
            'sync_error'       : 'YOUR INFOMATION HAS BEEN MODIFIED, PLEASE TRY AGAIN AFTER 2 MINUTES',
            'ip_alloc'         : 'THE IP HAS BEEN ASSIGNED TO OTHER USER'
            }

version  = '1.2'
sleep_time = 8

#########################################################
#               Main Login/Logout Modules               #
#########################################################

def trans_content(response):
    content = response.read().decode()
    ret = ''
    for ch in content:
        if ch.isalpha() or ch == '_':
            ret += ch
    return ret

def tunet_login(username, password):
    hashcd_md5 = hashlib.md5()
    hashcd_md5.update(password.encode())
    tr_password = hashcd_md5.hexdigest()
    login_data = 'username=' + username + '&password=' + tr_password + '&drop=0&type=1&n=100'
    login_data = login_data.encode()
    request_url = urllib.request.Request(login_url, login_data)
    response_url = urllib.request.urlopen(request_url)
    ret = trans_content(response_url)
    print (ret_type.get(ret, 'CONNECTED'))
    return ret

def tunet_logout():
    response_url = urllib.request.urlopen(logout_url)
    ret = trans_content(response_url)
    print (ret_type.get(ret, 'CONNECTED'))
    return ret

def tunet_check():
    check_data = 'action=check_online'
    check_data = check_data.encode()
    request_url = urllib.request.Request(check_url, check_data)
    response_url = urllib.request.urlopen(request_url)
    ret = trans_content(response_url)
    if ret == '':
        print ('NOT ONLINE')
    else:
        print (ret_type.get(ret, 'CONNECTED'))
    return ret

#########################################################
#                   Help&Version Modules                #
#########################################################

def tunet_help():
    print ('-h, --help   : show all options of Tsinghua University Internet Connector')
    print ('-v, --version: show version of Tsinghua University Internet Connector')
    print ('-u           : input your username after \'-u\'')
    print ('-p           : input your password after \'-p\'')
    print ('-a           : enter username and password later, you can login other campus network account')
    print ('-i, --login  : login operation')
    print ('-o, --logout : logout operation')
    print ('-c, --check  : check the internet')
    print ('-q, --query  : query basic infomation, online state and flux usage details')

def tunet_version():
    print ('Tsinghua University Internet Connector ', version)

def tunet_others():
    print ('UNKNOWN OPTIONS')
    print ('WHICH OPTION DO YOU WANT?')
    tunet_help()
    print ('IF ANY ERROR, PLEASE CONTACT im@huhaoyu.com.')

#########################################################
#                       Main Part                       #
#########################################################

def tunet_connect(username, password):
    ret = 'ip_exist_error'
    for count in range(5):
        print ('%s attempts to connect...' % times_cnt.get(count + 1))
        if ret != tunet_login(username, password):
            break
        if count == 4:
            print ('please try to reconnect after 1 minute')
            break
        print ('try to reconnect after %s seconds' %sleep_time)
        time.sleep(sleep_time)
        print ()

PYTUNET

#########################################################
#                       Welcome                         #
#   Tsinghua University Internet Connector in Python    #
#                    Version: v1.2                      #
#                   Date: 2015/04/05                    #
#           By: Haoyu hu    Email: im@huhaoyu.com       #
#           Address: Tsinghua University                #
#########################################################

import pytunet_connect
import pytunet_query
import sys, getopt, getpass, os, re

def pytunet():
    relative_path = 'USERNAME_PASSWORD.txt'
    file_handler = open(pytunet_query.create_path(relative_path), 'r')
    lines = file_handler.readlines()
    if len(lines) != 2:
        print('%s IS DAMAGED, PLEASE CHECK THE CONTENT FORMAT IN THE FILE:' %relative_path)
        print('CONTENT FORMAT AS FOLLOWS:')
        print('username=huhy14\npassword=123456')
        exit(1)
    username = re.sub('\s', '', lines[0])
    password = re.sub('\s', '', lines[1])
    _, username = username.split('=')
    _, password = password.split('=')
    file_handler.close()

    try:
        options, args = getopt.getopt(sys.argv[1:], 'achiop:qu:v', ['help', 'login', 'logout', 'check', 'version', 'query'])
    except getopt.GetoptError:
        pytunet_connect.tunet_others()
        sys.exit(1)

    want_login = False
    want_query = False
    flag = False

    name, value = None, None

    for name, value in options:
        if name in ('-h', '--help'):
            pytunet_connect.tunet_help()
            sys.exit(0)
        elif name in ('-v', '--version'):
            pytunet_connect.tunet_version()
            sys.exit(0)
        elif name == '-a':
            flag = True
        elif name == '-u':
            username = value
        elif name == '-p':
            password = value
        elif name in ('-i', '--login'):
            want_login = True
        elif name in ('-o', '--logout'):
            pytunet_connect.tunet_logout()
            sys.exit(0)
        elif name in ('-c', '--check'):
            pytunet_connect.tunet_check()
            sys.exit(0)
        elif name in ('-q', '--query'):
            want_query = True

    if flag:
        username = input('username: ')
        password = getpass.getpass('password: ')
        print (password)

    if want_query:
        pytunet_query.tunet_query(username, password)

    if want_login or not want_query and not want_login:
        pytunet_connect.tunet_connect(username, password)

    # if not want_query and not want_login:
    #   print ('WARNING: YOU JUST DIDN\'T DO ANYTHING! IF YOU WANT TO CONNECT TO THE CAMPUS NETWORK, THE COMMAND MUST INCLUDE -i OR --login')
    #   print()
    #   pytunet_connect.tunet_help()

if __name__ == '__main__':
    pytunet()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容