四川大学URP教务系统辅助程序

Python& AI 2018-09-12 895 次浏览 Comments Off on 四川大学URP教务系统辅助程序

2018.11.9 更新 0.71

1.添加图形界面

2.允许按年份查看课表与成绩信息

3.优化从返回的json文件获得数据

2018年9月四川大学更新URP教务系统之后,界面美观度、新浏览器的支持程度大大提升,而且一改之前的网页局部更新策略,接口更易使用,编写类爬虫辅助程序更加轻松。现将程序下载地址与代码分享如下:

2018.9.12更新

添加基本功能:

1.课程表查询

2.成绩查询与加权平均分与绩点计算

后期将添加的功能:

1.课程表输出.icv文件支持导入常见日历软件
2.选课/抢课功能
3.自动评价功能

附:0.71 版本源码

# -*- coding: utf-8 -*-
"""
Created on Thu Oct 11 16:43:01 2018

@author: zifeng
"""

import requests
import os
import sys
import json
import time
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QMainWindow,QApplication,QMessageBox

from ui_SCUURP import Ui_MainWindow
from ui_Login import Ui_login_Dialog

head = {'Accept':'*/*',  
       'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',  
       'X-Requested-With':'XMLHttpRequest',  
       'Referer':'http://www.zhjw.scu.edu.cn',  
       'Accept-Language':'zh-CN',  
       'Accept-Encoding':'gzip, deflate',  
       'User-Agent':'Mozilla/5.0(Windows NT 6.1;WOW64;Trident/7.0;rv:11.0)like Gecko',  
       'Host':'zhjw.scu.edu.cn'}

loginurl = 'http://zhjw.scu.edu.cn/j_spring_security_check'
scoreurl = 'http://zhjw.scu.edu.cn/student/integratedQuery/scoreQuery/allPassingScores/callback'
classTabelurl = 'http://zhjw.scu.edu.cn/student/courseSelect/thisSemesterCurriculum/ajaxStudentSchedule/callback'



class Main(QMainWindow,Ui_MainWindow):
    def __init__(self):
        super(Main, self).__init__()
        self.setupUi(self)
        self.firstrun=True
        print(self.firstrun)
    def OPEN(self):
        self.show()
        self.statusBar().showMessage('正在登陆...')
        QApplication.processEvents()
        self.refrushp1()
    def refrush(self):
        if self.tabWidget.currentIndex() == 0:
            self.refrushp1()
        if self.tabWidget.currentIndex() == 1:
            self.refrushp2()
        
    def refrushp1(self):
        self.ClassTables=self.getClassTables()
        self.statusBar().showMessage('正在获取课程信息...')
        QApplication.processEvents()
        self.model=QtGui.QStandardItemModel(len(self.ClassTables),len(self.ClassTables[0]))
        self.model.setHorizontalHeaderLabels(['               课程名               ','  上课教师  ','  上课建筑  ','  教室名  ',
                                              '   上课星期   ',' 起始节 ',' 持续节数 ','   上课周   ','课程属性','课程学分'])
        self.p1_tableView_class.setModel(self.model)
        self.p1_tableView_class.resizeColumnsToContents()
        self.p1_tableView_class.resizeRowsToContents()
        a = 0
        b = 0
        self.unit = 0.0
        self.reunit = 0.0
        for row in self.ClassTables:
            self.unit += row[-1]
            if row[-2] =="必修":
                self.reunit += row[-1]
            for column in row:
                item=QtGui.QStandardItem(str(self.ClassTables[a][b]))
                self.model.setItem(a, b,item)
                b+=1
            a+=1
            b=0
        QApplication.processEvents()
        self.p1_label_all_points.setText(str(self.unit))
        self.p1_label_points.setText(str(self.reunit))
        self.statusBar().showMessage('获取课程信息成功!')
    
    def refrushp2(self):
        self.CourseTables=self.get_course()
        self.statusBar().showMessage('正在获取成绩信息...')
        for i in range(5):
            QApplication.processEvents()
            time.sleep(0.2)
        self.model=QtGui.QStandardItemModel(len(self.CourseTables[1]),len(self.CourseTables[1][0]))
        self.model.setHorizontalHeaderLabels(['               课程名               ',' 分数 ',' 绩点 ',' 学分 ',
                                              '课程属性','          学年          ',' 等级 '])
        a = 0
        b = 0
        self.allunit = 0.0
        self.reunit = 0.0
        
        self.weight_allcourse = 0.0
        self.weight_recourse = 0.0
        
        self.weight_allpoint = 0.0
        self.weight_repoint = 0.0
        
        self.comboxlist=['全部']
        print(self.CourseTables)
        if self.firstrun == True:
            for course in self.CourseTables[0]:
                self.comboxlist.append(course[0])
            self.p2_comboBox_year.addItems(self.comboxlist)
        

        for row in self.CourseTables[1]:
            if row[2] == None:
                row[2] = 0.0
            self.allunit += row[3]
            self.weight_allcourse += float(str(row[1]))*row[3]
            self.weight_allpoint  +=  float(str(row[2]))*row[3]
            if row[4] =="必修":
                self.reunit += row[3]
                self.weight_recourse += float(str(row[1]))*row[3]
                self.weight_repoint  +=  float(str(row[2]))*row[3]
            for column in row:
                item=QtGui.QStandardItem(str(self.CourseTables[1][a][b]))
                self.model.setItem(a, b,item)
                QApplication.processEvents()
                b+=1
            a+=1
            b=0
                    
        self.p2_label_courses.setText(str(self.weight_allcourse/self.allunit))
        self.p2_label_points.setText(str(self.weight_allpoint/self.allunit))
        self.p2_tableView.setModel(self.model)
        self.p2_tableView.resizeColumnsToContents()
        self.p2_tableView.resizeRowsToContents()
        
        self.statusBar().showMessage('获取成绩信息成功!')
        self.firstrun=False
    def refrush2_years(self):
        if self.firstrun==False:
            a = 0
            b = 0
            self.allunit = 0.0
            self.reunit = 0.0
            
            self.weight_allcourse = 0.0
            self.weight_recourse = 0.0
            
            self.weight_allpoint = 0.0
            self.weight_repoint = 0.0
            if self.p2_comboBox_year.currentText() =='全部':
                self.model=QtGui.QStandardItemModel(len(self.CourseTables[1]),len(self.CourseTables[1][0]))
                self.model.setHorizontalHeaderLabels(['               课程名               ',' 分数 ',' 绩点 ',' 学分 ',
                                                  '课程属性','          学年          ',' 等级 '])
                for row in self.CourseTables[1]:
                    #self.unit += int(row[-1])
                    #if row[-2] =="必修":
                    #self.reunit += row[-1]
                    for column in row:
                        item=QtGui.QStandardItem(str(self.CourseTables[1][a][b]))
                        self.model.setItem(a, b,item)
                        b+=1
                    a+=1
                    b=0
            
            else:
                years_course=[]
                for row in self.CourseTables[1]:
                    if row[5] == self.p2_comboBox_year.currentText():
                        years_course.append(row)    
                self.model=QtGui.QStandardItemModel(len(years_course),len(years_course[0]))
                self.model.setHorizontalHeaderLabels(['               课程名               ',' 分数 ',' 绩点 ',' 学分 ',
                                                  '课程属性','          学年          ',' 等级 '])
                for row in years_course:
                    if row[2] == None:
                        row[2] = 0.0
                    self.allunit += row[3]
                    self.weight_allcourse += float(str(row[1]))*row[3]
                    self.weight_allpoint  +=  float(str(row[2]))*row[3]
                    if row[4] =="必修":
                        self.reunit += row[3]
                        self.weight_recourse += float(str(row[1]))*row[3]
                        self.weight_repoint  +=  float(str(row[2]))*row[3]
                    for column in row:
                        item=QtGui.QStandardItem(str(years_course[a][b]))
                        self.model.setItem(a, b,item)
                        QApplication.processEvents()
                        b+=1
                    a+=1
                    b=0
            self.p2_label_courses.setText(str(self.weight_allcourse/self.allunit))
            self.p2_label_points.setText(str(self.weight_allpoint/self.allunit))
            self.p2_tableView.setModel(self.model)
            #self.radioButton_all.toggled()
    def getClassTables(self):
        #获取教务系统课程表
        #输入参数:无(直接使用全局变量login_info)
        #返回:包含课程信息的列表
        try:
            s = requests.Session()
            print(payload_login_info)
            r = s.post(loginurl,timeout = 5,params = payload_login_info,headers = head)
            class_get = s.get(classTabelurl,timeout = 5,params = payload_login_info)
            class_json = json.loads(class_get.text)
        except:
            self.errEvent()
        nums_class = len(class_json['dateList'][0]['selectCourseList'])
        res_teacher = []
        res_class_name = []
        res_building_name = []
        res_room_name = []
        res_class_day = []
        res_class_sessions = []
        res_continuing_sessions = []
        res_weeks = []
        res_course_properties_name = []
        res_course_unit = []
        info_class = []
        
        for i in range(int(nums_class)):
            res_teacher.append(class_json['dateList'][0]['selectCourseList'][i]['attendClassTeacher'])
            res_class_name.append(class_json['dateList'][0]['selectCourseList'][i]['courseName'])
            try:
                res_building_name.append(class_json['dateList'][0]['selectCourseList'][i]['timeAndPlaceList'][0]['teachingBuildingName'])
                res_room_name.append(class_json['dateList'][0]['selectCourseList'][i]['timeAndPlaceList'][0]['classroomName'])
                res_class_day.append(class_json['dateList'][0]['selectCourseList'][i]['timeAndPlaceList'][0]['classDay'])
                res_class_sessions.append(class_json['dateList'][0]['selectCourseList'][i]['timeAndPlaceList'][0]['classSessions'])
                res_continuing_sessions.append(class_json['dateList'][0]['selectCourseList'][i]['timeAndPlaceList'][0]['continuingSession'])
                res_weeks.append(class_json['dateList'][0]['selectCourseList'][i]['timeAndPlaceList'][0]['weekDescription'])
            except:
                res_building_name.append('无数据')
                res_room_name.append('无数据')
                res_class_day.append('无数据')
                res_class_sessions.append('无数据')
                res_continuing_sessions.append('无数据')
                res_weeks.append('无数据')
            res_course_properties_name.append(class_json['dateList'][0]['selectCourseList'][i]['coursePropertiesName'])
            res_course_unit.append(class_json['dateList'][0]['selectCourseList'][i]['unit'])
            info_class.append([])
            info_class[i].append(res_class_name[i])
            info_class[i].append(res_teacher[i])
            info_class[i].append(res_building_name[i])
            info_class[i].append(res_room_name[i])
            info_class[i].append(res_class_day[i])
            info_class[i].append(res_class_sessions[i])
            info_class[i].append(res_continuing_sessions[i])
            info_class[i].append(res_weeks[i])
            info_class[i].append(res_course_properties_name[i])
            info_class[i].append(res_course_unit[i])
        return info_class
    
    def get_course(self):
        #获取教务系统成绩
        #输入参数:无(直接使用全局变量login_info)
        #返回:包含成绩信息的列表
        try:
            s = requests.Session()
            r = s.post(loginurl,timeout = 3,params = payload_login_info,headers = head)
            class_html = s.get(scoreurl,timeout = 5,params = {'planCode': '2017-2018-2-1'})
            course_json = json.loads(class_html.text)
        except:
            self.errEvent()
        terms = []
        info_class = []
        for i in course_json['lnList']:
            terms.append([])
            terms[-1].append(i['cjbh'].replace('(两学期)',''))
            terms[-1].append(i['zms'])
            terms[-1].append(i['yxxf'])
            for c in i['cjList']:
                info_class.append([])
                luoma=['Ⅰ','Ⅱ','Ⅲ','Ⅳ','Ⅴ']
                shuzi=['I','II','III','IV','V']
                for a in range(5):
                    c['courseName'] = c['courseName'].replace(luoma[a],shuzi[a])
                info_class[-1].append(c['courseName'])
                info_class[-1].append(c['courseScore'])
                info_class[-1].append(c['gradePointScore'])
                info_class[-1].append(eval(c['credit']))
                info_class[-1].append(c['courseAttributeName'])
                info_class[-1].append(terms[-1][0])
                info_class[-1].append(c['gradeName'])
        return_list=[]
        return_list.append(terms)
        return_list.append(info_class)
        return return_list

    def errEvent(self):
        reply = QMessageBox.question(self, '错误', '无法登录到教务系统,请检查登录信息或网络', QMessageBox.Yes)
        if reply == QMessageBox.Yes:
            exit()
            
class login(QMainWindow,Ui_login_Dialog):
    def __init__(self):
        super(login, self).__init__()
        self.setupUi(self)
    def OPEN(self):
        self.show()
        QApplication.processEvents()
    def reload_login_info(self):
        QApplication.processEvents()
        print(payload_login_info['j_username'])
        self.lineEdit.setText(payload_login_info['j_username'])
        self.lineEdit_2.setText(payload_login_info['j_password'])
    def get_login_info(self):
        global payload_login_info
        payload_login_info = {'j_captcha1': 'error', 'j_password': self.lineEdit_2.text(),'j_username': self.lineEdit.text()}
        print(self.lineEdit_2.text())
        if self.checkBox_save.isChecked() == True:
            f = open('./logininfo.dat','w')
            f.write(self.lineEdit.text()+'\n')
            f.write(self.lineEdit_2.text()+'\n')
            f.close()

def reload_login():
    #获取教务系统登陆账号密码,有本地与重新输入两种方式
    #输入参数:无
    #返回:无(直接改变全局变量login_info)
        global payload_login_info 
        if os.path.exists('./logininfo.dat'):
            f = open('./logininfo.dat','r+')
            login_username = f.readline()[0:-1]
            login_password = f.readline()[0:-1]
            f.close()
            
        else:
            login_username = ''
            login_password = ''
        payload_login_info = {'j_captcha1': 'error', 'j_password': login_password,'j_username': login_username}


if __name__=="__main__":

    app = QApplication(sys.argv)

    reload_login()
    LoginWindows = login()
    MainWindow = Main()
    LoginWindows.OPEN()
    LoginWindows.reload_login_info()
    LoginWindows.pushButton_login.clicked.connect(LoginWindows.get_login_info)
    LoginWindows.pushButton_login.clicked.connect(MainWindow.OPEN)
    LoginWindows.pushButton_login.clicked.connect(LoginWindows.close)

    MainWindow.tabWidget.currentChanged.connect(MainWindow.refrush)
    MainWindow.p2_comboBox_year.currentTextChanged.connect(MainWindow.refrush2_years)
    sys.exit(app.exec())
梓沨

站长 INTP,生物搬砖工