snnusdk.urp 源代码

'''
Created on Nov 29, 2018

@author: QiZhao
'''

import re

from snnusdk.base import API
from snnusdk.exceptions import (AuthenticationError, UnauthorizedError,
                                YearNotExistError)
# from snnusdk.tool.GUI import CaptchaGUI
from snnusdk.tool.Table import table_to_list
from snnusdk.utils.captcha import UrpCaptcha


[文档]class Urp(API): """陕师大Urp教务 :param str account: 学号 :param str password: 密码 :raise: :class:`snnusdk.exceptions.AuthenticationError` :raise: :class:`snnusdk.exceptions.UnauthorizedError` :raise: :class:`snnusdk.exceptions.YearNotExistError` >>> urp = Urp(account='B11111111', password='xxx') """ class URLs: HOST = "http://219.244.71.113" SELECTED_COURSES = HOST + '/xkAction.do?actionType=6' OLD_COURSES = HOST + '/lnkbcxAction.do' # 历年课表 CAPTCHA = HOST + '/validateCodeAction.do' # 教务系统验证码 LOGIN = HOST + '/loginAction.do' # 教务系统登录 GRADE = HOST + '/bxqcjcxAction.do' # 本学期成绩 ALL_GRADE = HOST + '/gradeLnAllAction.do?type=ln&oper=qbinfo' # 全部及格成绩 def __init__(self, account=None, password=None): super(Urp, self).__init__() if account and password: self.account = account self.password = password
[文档] def get_courses(self): """获取本学期的选课情况 :raise: :class:`snnusdk.exceptions.UnauthorizedError` :rtype: list of dict :return: 参照例子 >>> urp.get_courses() [ { 'id': '1241416', 'name': '算法设计与分析', 'number': '01', 'credits': 3.0, 'attributes': '必修', 'teacher': '王小明*', 'status': '置入', 'info': [ { 'week': '1-18周上', 'day': '2', 'timeOfClass': '1', 'numOfClass': '2', 'campus': '长安校区', 'buildings': '长安文津楼', 'room': '1511' } ] } ] """ if self.verify is False: raise UnauthorizedError('您还没有登录!') soup = self.get_soup(method='get', url=self.URLs.SELECTED_COURSES) tables = soup.findAll("table", attrs={'id': "user"}) table = tables[1] table_list = table_to_list( table, remove_index_list=[8, 9]) # 0,6虽不用,不可写 courses = [] temp_dic = {} keys = ['周次', '星期', '节次', '节数', '校区', '教学楼', '教室'] for dic in table_list: dic_len = len(dic) if dic_len > 9: courses.append({ 'id': dic['课程号'], 'name': dic['课程名'], 'number': dic['课序号'], 'credits': float(dic['学分']), 'attributes': dic['课程属性'], 'teacher': dic['教师'], 'status': dic['选课状态'], 'info': [] }) else: dic = dict(zip(keys, [dic[key] for key in dic.keys()])) for key in dic.keys(): if key in keys: temp_dic = { 'week': dic['周次'], 'day': dic['星期'], 'timeOfClass': dic['节次'], 'numOfClass': dic['节数'], 'campus': dic['校区'], 'buildings': dic['教学楼'], 'room': dic['教室'] } courses[-1]['info'].append(temp_dic) temp_dic = {} return courses
[文档] def get_old_courses(self, year, semester): """获取指定学期的课表 :param str year: 学年 格式为 "2017-2018" :param int semester: 学期 数字1或2 :raise: :class:`snnusdk.exceptions.UnauthorizedError` :raise: :class:`snnusdk.exceptions.YearNotExistError` :rtype: list of dict :return: 参照例子 >>> u.get_old_courses(year='2017-2018', semester=1) [ { 'id': '1241416', 'name': '算法设计与分析', 'number': '01', 'credits': 3.0, 'attributes': '必修', 'teacher': '王小明*', 'status': '置入', 'info': [ { 'week': '1-18周上', 'day': '2', 'timeOfClass': '1', 'numOfClass': '2', 'campus': '长安校区', 'buildings': '长安文津楼', 'room': '1511' } ] } ] """ if self.verify is False: raise UnauthorizedError('您还没有登录!') soup = self.get_soup(self.URLs.OLD_COURSES) year_list = [i.get('value') for i in soup.find_all(name='option')] key = "{}-{}-1".format(year, semester) if key not in year_list: raise YearNotExistError('不存在该学期!') soup = self.get_soup( self.URLs.OLD_COURSES, 'post', data={'zxjxjhh': key}) table = soup.find_all(name='table', attrs={'id': 'user'})[1] table_list = table_to_list(table, remove_index_list=[8]) courses = [] temp_dic = {} keys = ['周次', '星期', '节次', '节数', '校区', '教学楼', '教室'] for dic in table_list: dic_len = len(dic) if dic_len > 7: courses.append({ 'id': dic['课程号'], 'name': dic['课程名'], 'number': dic['课序'], 'credits': float(dic['学分']), 'attributes': dic['课程属性'], 'teacher': dic['教师'], 'status': dic['选课状态'], 'info': [] }) else: dic = dict(zip(keys, [dic[key] for key in dic.keys()])) for key in dic.keys(): if key in keys: temp_dic = { 'week': dic['周次'], 'day': dic['星期'], 'timeOfClass': dic['节次'], 'numOfClass': dic['节数'], 'campus': dic['校区'], 'buildings': dic['教学楼'], 'room': dic['教室'] } courses[-1]['info'].append(temp_dic) temp_dic = {} return courses
[文档] def get_grade(self): """获取本学期的成绩 :raise: :class:`snnusdk.exceptions.UnauthorizedError` :rtype: list of dict :return: 参照例子 >>> u.get_grade() [ { '课程号': '1243432', '课序号': '01', '课程名': '高级数据结构', '英文课程名': 'Advanced Data Structures', '学分': '2', '课程属性': '任选', '课堂最高分': '', '课堂最低分': '', '课堂平均分': '', '成绩': '', '名次': '', '未通过原因': '' }, ... ] """ if self.verify is False: raise UnauthorizedError('您还没有登录!') soup = self.get_soup(self.URLs.GRADE) table = soup.find(name='table', attrs={'class': 'titleTop2'}) table_list = table_to_list(table) return table_list[1:]
[文档] def get_grade_year_list(self): """获取可供查询成绩的学期名称 :raise: :class:`snnusdk.exceptions.UnauthorizedError` :rtype: list :return: 参照例子 >>> u.get_grade_year_list() [ '2016-2017学年秋(两学期)', '2016-2017学年春(两学期)', '2017-2018学年秋(两学期)', '2017-2018学年春(两学期)' ] """ if self.verify is False: raise UnauthorizedError('您还没有登录!') soup = self.get_soup(self.URLs.ALL_GRADE) a_tags = soup.find_all(name='a') year_list = [a.get('name') for a in a_tags] return year_list
[文档] def get_all_grades(self, year, semester): """获取指定学期的已及格成绩 :param str year: 学年 格式为 "2017-2018" :param int semester: 学期 数字1或2 :raise: :class:`snnusdk.exceptions.UnauthorizedError` :raise: :class:`snnusdk.exceptions.YearNotExistError` :rtype: list :return: 参照例子 >>> u.get_all_grades(year='2017-2018', semester=1) [ { '课程号':'01111', '课序号': '62', '课程名': '大学外语(一)', '英文课程名': 'College English 1', '学分': '3', '课程属性': '必修', '成绩': '73.0' }, ... ] """ if self.verify is False: raise UnauthorizedError('您还没有登录!') year_list = self.get_grade_year_list() year_set = set() for year_item in year_list: year_set.add( re.search(r'\d{4,4}-\d{4,4}', year_item, re.S).group(0)) if year not in year_set or semester not in [1, 2]: raise YearNotExistError('不存在该学期') key = "{}学年{}(两学期)".format(year, '春' if semester == 2 else '秋') tables = self.get_soup(self.URLs.ALL_GRADE).find_all( name='table', attrs={'class': 'displayTag'}) table = tables[year_list.index(key)] table_list = table_to_list(table) return table_list
[文档] def get_gpa(self): """计算绩点 :raise: :class:`snnusdk.exceptions.UnauthorizedError` :rtype: double :return: 只计算必修课后的绩点 >>> u.get_gpa() 73.00 """ if self.verify is False: raise UnauthorizedError('您还没有登录!') ret = 0.0 num = 0.0 tables = self.get_soup(self.URLs.ALL_GRADE).find_all( name='table', attrs={'class': 'displayTag'}) for table in tables: table_list = table_to_list(table) for dic in table_list: if dic['课程属性'] == '必修': num += float(dic['学分']) ret += float(dic['学分']) * float(dic['成绩']) return round(ret / num, 2)
[文档] def login(self): """登录 :raise: :class:`snnusdk.exceptions.AuthenticationError` :rtype: dict >>> u.login() { 'msg': '登录成功', 'success': True } """ # FIXME: 登录不可靠 image = self.get_image(self.URLs.CAPTCHA) # captcha_code = CaptchaGUI(image) captcha_code = UrpCaptcha(image) data = { "zjh1": "", "tips": "", "lx": "", "evalue": "", "eflag": "", "fs": "", "dzslh": "", "zjh": self.account, "mm": self.password, "v_yzm": captcha_code } result = self._login_execute(url=self.URLs.LOGIN, data=data) if result['code'] == 2: # 如果验证码错误,尝试递归重复登录 return self.login() result['success'] = not result['code'] del result['code'] if result['success']: self.verify = True else: raise AuthenticationError(result['msg']) return result
def _login_execute(self, url=None, data=None): r = self.post(url=url, data=data) # print(r.text) if r.ok: if "学分制综合教务" in r.text: self.verify = True # 登陆成功, 修改状态 (后期还可能继续修改) return {'code': 0, 'msg': '登录成功'} elif "你输入的验证码错误" in r.text: return {'code': 2, 'msg': '验证码不正确!!!'} elif "alert.gif" in r.text: return {'code': 1, 'msg': '密码错误!!'} else: return {'code': 3, 'msg': '未知错误'} else: return {'code': 1, "msg": "登录失败"}
if __name__ == '__main__': c = Urp("xx", "xx") # c.login() print(c.login()) print(c.get_old_courses('2018-2019', 1)) print(c.get_grade_year_list()) # print(c.())