diff --git a/工具v2/Ui_下载小闲答题数据.py b/工具v2/Ui_下载小闲答题数据.py new file mode 100644 index 00000000..ae705bc4 --- /dev/null +++ b/工具v2/Ui_下载小闲答题数据.py @@ -0,0 +1,120 @@ +# -*- coding: utf-8 -*- + +################################################################################ +## Form generated from reading UI file '下载小闲答题数据.ui' +## +## Created by: Qt User Interface Compiler version 6.6.2 +## +## WARNING! All changes made in this file will be lost when recompiling UI file! +################################################################################ + +from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale, + QMetaObject, QObject, QPoint, QRect, + QSize, QTime, QUrl, Qt) +from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor, + QFont, QFontDatabase, QGradient, QIcon, + QImage, QKeySequence, QLinearGradient, QPainter, + QPalette, QPixmap, QRadialGradient, QTransform) +from PySide6.QtWidgets import (QApplication, QHeaderView, QLabel, QLineEdit, + QPushButton, QSizePolicy, QTableWidget, QTableWidgetItem, + QWidget) + +class Ui_Form(object): + def setupUi(self, Form): + if not Form.objectName(): + Form.setObjectName(u"Form") + Form.resize(489, 636) + self.pushButton_chrome = QPushButton(Form) + self.pushButton_chrome.setObjectName(u"pushButton_chrome") + self.pushButton_chrome.setGeometry(QRect(10, 10, 75, 24)) + self.pushButton_driver = QPushButton(Form) + self.pushButton_driver.setObjectName(u"pushButton_driver") + self.pushButton_driver.setGeometry(QRect(10, 50, 75, 24)) + self.pushButton_outputfolder = QPushButton(Form) + self.pushButton_outputfolder.setObjectName(u"pushButton_outputfolder") + self.pushButton_outputfolder.setGeometry(QRect(10, 90, 75, 24)) + self.label_chrome = QLabel(Form) + self.label_chrome.setObjectName(u"label_chrome") + self.label_chrome.setGeometry(QRect(90, 10, 221, 21)) + self.label_driver = QLabel(Form) + self.label_driver.setObjectName(u"label_driver") + self.label_driver.setGeometry(QRect(90, 50, 221, 21)) + self.label_outputfolder = QLabel(Form) + self.label_outputfolder.setObjectName(u"label_outputfolder") + self.label_outputfolder.setGeometry(QRect(90, 90, 221, 21)) + self.pushButton_openbrowser = QPushButton(Form) + self.pushButton_openbrowser.setObjectName(u"pushButton_openbrowser") + self.pushButton_openbrowser.setGeometry(QRect(10, 130, 71, 51)) + self.pushButton_login = QPushButton(Form) + self.pushButton_login.setObjectName(u"pushButton_login") + self.pushButton_login.setGeometry(QRect(90, 130, 71, 51)) + self.pushButton_exec = QPushButton(Form) + self.pushButton_exec.setObjectName(u"pushButton_exec") + self.pushButton_exec.setGeometry(QRect(280, 130, 201, 51)) + font = QFont() + font.setBold(True) + self.pushButton_exec.setFont(font) + self.label = QLabel(Form) + self.label.setObjectName(u"label") + self.label.setGeometry(QRect(330, 10, 54, 16)) + self.label_2 = QLabel(Form) + self.label_2.setObjectName(u"label_2") + self.label_2.setGeometry(QRect(330, 50, 54, 16)) + self.label_3 = QLabel(Form) + self.label_3.setObjectName(u"label_3") + self.label_3.setGeometry(QRect(330, 90, 71, 16)) + self.lineEdit_startdate = QLineEdit(Form) + self.lineEdit_startdate.setObjectName(u"lineEdit_startdate") + self.lineEdit_startdate.setGeometry(QRect(390, 10, 91, 20)) + self.lineEdit_enddate = QLineEdit(Form) + self.lineEdit_enddate.setObjectName(u"lineEdit_enddate") + self.lineEdit_enddate.setGeometry(QRect(390, 50, 91, 20)) + self.lineEdit_graderegex = QLineEdit(Form) + self.lineEdit_graderegex.setObjectName(u"lineEdit_graderegex") + self.lineEdit_graderegex.setGeometry(QRect(410, 90, 71, 20)) + self.pushButton_getlist = QPushButton(Form) + self.pushButton_getlist.setObjectName(u"pushButton_getlist") + self.pushButton_getlist.setGeometry(QRect(170, 130, 101, 51)) + self.tableWidget = QTableWidget(Form) + if (self.tableWidget.columnCount() < 3): + self.tableWidget.setColumnCount(3) + __qtablewidgetitem = QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(0, __qtablewidgetitem) + __qtablewidgetitem1 = QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(1, __qtablewidgetitem1) + __qtablewidgetitem2 = QTableWidgetItem() + self.tableWidget.setHorizontalHeaderItem(2, __qtablewidgetitem2) + self.tableWidget.setObjectName(u"tableWidget") + self.tableWidget.setGeometry(QRect(10, 190, 471, 431)) + + self.retranslateUi(Form) + + QMetaObject.connectSlotsByName(Form) + # setupUi + + def retranslateUi(self, Form): + Form.setWindowTitle(QCoreApplication.translate("Form", u"\u4e0b\u8f7d\u5c0f\u95f2\u7b54\u9898\u7eb8", None)) + self.pushButton_chrome.setText(QCoreApplication.translate("Form", u"chrome\u8def\u5f84", None)) + self.pushButton_driver.setText(QCoreApplication.translate("Form", u"driver\u8def\u5f84", None)) + self.pushButton_outputfolder.setText(QCoreApplication.translate("Form", u"\u8f93\u51fa\u8def\u5f84", None)) + self.label_chrome.setText(QCoreApplication.translate("Form", u"\u6b64\u5904\u663e\u793achrome.exe\u7684\u8def\u5f84", None)) + self.label_driver.setText(QCoreApplication.translate("Form", u"\u6b64\u5904\u663e\u793achrome webdriver\u7684\u8def\u5f84", None)) + self.label_outputfolder.setText(QCoreApplication.translate("Form", u"\u6b64\u5904\u663e\u793a\u8f93\u51fa\u7684zip\u6587\u4ef6\u7684\u8def\u5f84", None)) + self.pushButton_openbrowser.setText(QCoreApplication.translate("Form", u"\u5f00\u542f\u6d4f\u89c8\u5668", None)) + self.pushButton_login.setText(QCoreApplication.translate("Form", u"\u767b\u5f55", None)) + self.pushButton_exec.setText(QCoreApplication.translate("Form", u"\u4e0b\u8f7d\u7b54\u9898\u60c5\u51b5", None)) + self.label.setText(QCoreApplication.translate("Form", u"\u8d77\u59cb\u65e5\u671f", None)) + self.label_2.setText(QCoreApplication.translate("Form", u"\u7ec8\u6b62\u65e5\u671f", None)) + self.label_3.setText(QCoreApplication.translate("Form", u"\u5e74\u7ea7(regex)", None)) + self.lineEdit_startdate.setPlaceholderText(QCoreApplication.translate("Form", u"yyyymmdd", None)) + self.lineEdit_enddate.setPlaceholderText(QCoreApplication.translate("Form", u"yyyymmdd", None)) + self.lineEdit_graderegex.setPlaceholderText(QCoreApplication.translate("Form", u"\u9ad8[\u4e00\u4e8c]", None)) + self.pushButton_getlist.setText(QCoreApplication.translate("Form", u"\u83b7\u53d6\u7b54\u9898\u5361\u5217\u8868", None)) + ___qtablewidgetitem = self.tableWidget.horizontalHeaderItem(0) + ___qtablewidgetitem.setText(QCoreApplication.translate("Form", u"\u7b54\u9898\u7eb8\u540d\u79f0", None)); + ___qtablewidgetitem1 = self.tableWidget.horizontalHeaderItem(1) + ___qtablewidgetitem1.setText(QCoreApplication.translate("Form", u"\u5df2\u4e0b\u8f7d", None)); + ___qtablewidgetitem2 = self.tableWidget.horizontalHeaderItem(2) + ___qtablewidgetitem2.setText(QCoreApplication.translate("Form", u"\u5df2\u66f4\u540d", None)); + # retranslateUi + diff --git a/工具v2/下载小闲答题数据.py b/工具v2/下载小闲答题数据.py new file mode 100644 index 00000000..6cb153c0 --- /dev/null +++ b/工具v2/下载小闲答题数据.py @@ -0,0 +1,320 @@ +from PySide6.QtWidgets import QWidget, QApplication, QFileDialog +from Ui_下载小闲答题数据 import Ui_Form +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.chrome.service import Service +from selenium.webdriver.common.keys import Keys +import re,os,sys +from datetime import datetime +import numpy as np +from time import sleep + + +def GetPageInfo(driver): #学情报告页面, 显示页码和总页数 + pageinfo = driver.find_element(By.CSS_SELECTOR,"[class*=styles__page___]").text + return pageinfo + + +def SelectNext(driver): # 在打开后的报告页面选择下一个班级 + try: + openlist = driver.find_element(By.XPATH,"/html/body/div[2]/div/div/div[2]/div[1]/div[2]/div/div/div") + sleep(0.1) + openlist.click() + sleep(0.1) + openlist.send_keys(Keys.ARROW_DOWN) + sleep(0.1) + openlist.send_keys(Keys.ENTER) + sleep(0.3) + return driver.find_element(By.XPATH,"/html/body/div[2]/div/div/div[2]/div[1]/div[2]/div/div/div").text + except: + return 1 + +def GetDate(driver): #显示当前班级的提交时间 + commit_date = driver.find_element(By.XPATH,"/html/body/div[2]/div/div/div[2]/div[1]/div[2]/span[2]").text + year,month,date = re.findall(r"(\d{4})-(\d{2})-(\d{2})",commit_date)[0] + return year+month+date + +def GetCommitInfo(driver): #获取报告页面的班级及提交日期信息 + commit_dict = {} + classname = SelectNext(driver) + sleep(0.5) + while not classname in commit_dict.keys(): + commit_date = GetDate(driver) + if not classname == 1: + commit_dict[classname] = commit_date + classname = SelectNext(driver) + else: + classname = SelectNext(driver) + return commit_dict + +def ToIntTime(string): + date_obj = datetime.strptime(string, "%Y%m%d") + int_time = int(date_obj.timestamp()) + return int_time + +def MedianCommitDate(adict): + return datetime.fromtimestamp(np.median([ToIntTime(adict[t]) for t in adict.keys()])).strftime("%Y%m%d") + +def gotopagenum(driver,num): + pagecontrol = driver.find_element(By.CSS_SELECTOR,"[class*=styles__pagination___]") + pageinput = pagecontrol.find_element(By.CSS_SELECTOR,"input[type=text]") + pageinput.clear() + submitbutton = pagecontrol.find_element(By.CSS_SELECTOR,"[class*=tyles__button___]") + pageinput.send_keys(str(1)) + submitbutton.click() + sleep(0.5) + pageinput.clear() + sleep(0.1) + pageinput.send_keys(str(num)) + submitbutton.click() + sleep(0.5) + +def ClickBack(driver): # 点击返回按钮 + backbutton = driver.find_element(By.CSS_SELECTOR,'[class*=styles__back]') # 点击返回 + backbutton.click() + sleep(1) + +def GetHomeworkNames(driver,starting_date = "20000101"): + hwk_list = [] + homework_roots = driver.find_elements(By.CSS_SELECTOR,'[class*=styles__reportList]') + for homework_root in homework_roots: + name = homework_root.find_element(By.CSS_SELECTOR,'[class*=styles__name]').text + date_raw = homework_root.find_element(By.CSS_SELECTOR,'[class*=styles__time]').text + date = re.findall(r"\d{4}-\d{2}-\d{2}",date_raw)[0].replace("-","") + time = re.findall(r"\d{2}:\d{2}:\d{2}",date_raw)[0].replace(":","") + grade = homework_root.find_element(By.CSS_SELECTOR,'[class*=styles__grades]').text[3:] + if date >= starting_date: + hwk_list.append({"name": name, "date": date, "time": time, "grade": grade}) + return hwk_list + +def GetHomeworkRoots(driver): #找到页面上所有作业考试的root + homework_roots = driver.find_elements(By.CSS_SELECTOR,'[class*=styles__reportList]') + return homework_roots + +def ClickDetail(root): #点击查看详情 + root.find_element(By.XPATH,"div[2]/div[2]").click() + +def ClickDownload(root): #点击报表 + root.find_element(By.XPATH,"div[2]/div[3]").click() + +def StartandEndDownload(driver): + driver.find_element(By.XPATH,"/html/body/div[4]/div/div[2]/div/div[2]/div[3]/div/button[2]").click() + QuitDownload(driver) + +def QuitDownload(driver): #退出下载对话框 + while driver.find_element(By.XPATH,"/html/body/div[4]/div/div[2]/div/div[2]/div[3]/div/button[1]").text == '取 消': + try: + sleep(0.5) + driver.find_element(By.XPATH,"/html/body/div[4]/div/div[2]/div/div[2]/div[3]/div/button[1]").click() + except: + pass + +def GenerateCommitMessages(driver,index): #在班级报告页面逐一读取页面上的指定作业的名称和计算中位提交日期 + page_info = GetPageInfo(driver) + page = page_info[:page_info.index("/")] + roots = GetHomeworkRoots(driver) + root = roots[index-1] + # root_text = root.text + # homework_name = root_text.split("\n")[1] + ClickDetail(root) + adict = GetCommitInfo(driver) + # print(homework_name) + message = MedianCommitDate(adict) + sleep(0.1) + ClickBack(driver) + sleep(0.5) + gotopagenum(driver,page) + sleep(0.5) + return message + +def DownloadZipwithDetail(driver,index): #下载页面上的指定zip文件, 并返回中位上传时间 + page_info = GetPageInfo(driver) + page = page_info[:page_info.index("/")] + roots = GetHomeworkRoots(driver) + root = roots[index-1] + root_text = root.text + homework_name = root_text.split("\n")[1] + ClickDownload(root) + sleep(0.5) + StartandEndDownload(driver) + print(f"已下载: {homework_name}") + sleep(0.5) + QuitDownload(driver) + ClickDetail(root) + adict = GetCommitInfo(driver) + message = MedianCommitDate(adict) + sleep(0.1) + ClickBack(driver) + sleep(0.5) + gotopagenum(driver,page) + sleep(0.5) + return message + +def RenameRecentzip(folder,message): #将folder中最新的zip文件名加上(message) + filelist = os.listdir(folder) + filelist.sort(key = lambda x:os.path.getmtime(os.path.join(folder,x)),reverse = True) + filepath = os.path.join(folder,filelist[0]) + renamedfilepath = filepath[:-4]+f"({message}).zip" + os.rename(filepath,renamedfilepath) + print(f"已重命名为: {os.path.split(renamedfilepath)[-1]}") + + +def DownloadZips(driver,alist=[]): #下载页面上的指定zip文件 + page_info = GetPageInfo(driver) + page = page_info[:page_info.index("/")] + roots_len = len(GetHomeworkRoots(driver)) + if alist == []: + rangelist = range(roots_len) + else: + rangelist = alist.copy() + for i in rangelist: + roots = GetHomeworkRoots(driver) + root = roots[i] + root_text = root.text + homework_name = root_text.split("\n")[1] + ClickDownload(root) + sleep(0.5) + StartandEndDownload(driver) + print(f"已下载: {homework_name}") + sleep(0.5) + gotopagenum(driver,page) + sleep(0.5) + +def DownloadandRenameZips(driver,message,folder,index): #下载页面上的指定zip文件 + page_info = GetPageInfo(driver) + page = page_info[:page_info.index("/")] + roots = GetHomeworkRoots(driver) + root = roots[index-1] + print(root.text) + ClickDownload(root) + sleep(0.5) + StartandEndDownload(driver) + sleep(5) + filelist = os.listdir(folder) + filelist.sort(key = lambda x:os.path.getmtime(os.path.join(folder,x)),reverse = True) + filepath = os.path.join(folder,filelist[0]) + renamedfilepath = filepath[:-4]+f"({message}).zip" + os.rename(filepath,renamedfilepath) + print(f"已重命名为: {os.path.split(renamedfilepath)[-1]}") + sleep(0.5) + gotopagenum(driver,page) + sleep(0.5) + +def getIndices(string): + if string.strip() == "": + return [] + else: + string_list = [int(i)-1 for i in string.strip().split(",")] + return string_list + +def GetValidHomeworks(driver,startdate,enddate,graderegex): #在所有作业中找到在startdate,enddate中符合graderegex年级的作业, 返回(作业信息,页码)的列表 + validhomeworks = [] + gotopagenum(driver,1) + sleep(2) + endflag = False + while not endflag: + currentpage = int(re.findall("^([\d]+)/",GetPageInfo(driver))[0]) + homeworkinfo = GetHomeworkNames(driver) + for item in homeworkinfo: + if re.findall(graderegex,item["grade"])!= [] and startdate <= item["date"] <= enddate: + validhomeworks.append((item,currentpage)) + print(item) + if startdate > item["date"]: + endflag = True + break + gotopagenum(driver,currentpage+1) + sleep(2) + return validhomeworks[-1::-1] + + +def gethmwkIndexonPage(driver,hmwkinfo): #在当前页面寻找作业位置, 返回位置(1-10), 若未找到则返回-1 + homeworks = GetHomeworkNames(driver) + count = 1 + for h in homeworks: + if h == hmwkinfo: + return count + count += 1 + return -1 + +class MyWindow(QWidget,Ui_Form): + def __init__(self): + super().__init__() + self.setupUi(self) + self.bind() + + def bind(self): + self.pushButton_chrome.clicked.connect(self.getchromePath) + self.pushButton_driver.clicked.connect(self.getdriverPath) + self.pushButton_outputfolder.clicked.connect(self.getoutputfolder) + self.pushButton_openbrowser.clicked.connect(self.openbrowser) + self.pushButton_login.clicked.connect(self.login) + self.pushButton_getlist.clicked.connect(self.getlist) + self.pushButton_exec.clicked.connect(self.exec) + + def getchromePath(self): + pathlist = QFileDialog.getOpenFileName(self,"选择文件",".","chrome.exe文件(chrome.exe);;所有文件(*)") + self.label_chrome.setText(pathlist[0]) + self.chromepath = pathlist[0] + def getdriverPath(self): + pathlist = QFileDialog.getOpenFileName(self,"选择文件",".","chromedriver.exe文件(chromedriver.exe);;所有文件(*)") + self.label_driver.setText(pathlist[0]) + self.driverpath = pathlist[0] + def getoutputfolder(self): + self.outputfolder = QFileDialog.getExistingDirectory(None, "选择文件夹") + if sys.platform == "win32": + self.outputfolder = self.outputfolder.replace("/","\\") + self.label_outputfolder.setText(self.outputfolder) + def openbrowser(self): + service = Service(executable_path=self.driverpath) + options = webdriver.ChromeOptions() + options.binary_location = self.chromepath + prefs = {"download.default_directory": self.outputfolder} + options.add_experimental_option("prefs", prefs) + self.driver = webdriver.Chrome(service= service,options = options) + self.driver.get("http://ls.xiaoxianai.cn") + def login(self): + loginform = self.driver.find_element(By.XPATH,'//*[@id="container"]/div/div/form') + loginlist = loginform.find_elements(By.TAG_NAME,"div") + loginlist[1].find_element(By.TAG_NAME,"input").send_keys("16621337584") + loginlist[2].find_element(By.TAG_NAME,"input").send_keys("password") + loginform.find_element(By.TAG_NAME,"button").click() + def getlist(self): + self.homeworklist = GetValidHomeworks(self.driver,self.lineEdit_startdate.text(),self.lineEdit_enddate.text(),self.lineEdit_graderegex.text()) + def exec(self): + for hmwk,page in self.homeworklist: + foundhmwk = False + downloaded = False + for p in range(page+1,0,-1): + gotopagenum(self.driver,p) + sleep(2) + hmwkindex = gethmwkIndexonPage(self.driver,hmwk) + if hmwkindex > 0: + foundhmwk = True + print(f"已找到 {hmwk['name']} 于页码 {p}, 第 {hmwkindex} 项") + break + if not foundhmwk: + print(f"!!!!!!未找到 {hmwk['name']}") + else: + print(f"正在下载 {hmwk['name']} 的 zip 文件") + try: + message = DownloadZipwithDetail(self.driver,hmwkindex) + RenameRecentzip(self.outputfolder,message) + downloaded = True + except: + print(Exception) + if not downloaded: + print(f"@@@@@@未能下载 {hmwk['name']}") + + + + + + + + +if __name__ == '__main__': + app = QApplication([]) + windows = MyWindow() + windows.show() + app.exec() + diff --git a/工具v2/下载小闲答题数据.ui b/工具v2/下载小闲答题数据.ui new file mode 100644 index 00000000..4cf2784d --- /dev/null +++ b/工具v2/下载小闲答题数据.ui @@ -0,0 +1,257 @@ + + + Form + + + + 0 + 0 + 489 + 636 + + + + 下载小闲答题纸 + + + + + 10 + 10 + 75 + 24 + + + + chrome路径 + + + + + + 10 + 50 + 75 + 24 + + + + driver路径 + + + + + + 10 + 90 + 75 + 24 + + + + 输出路径 + + + + + + 90 + 10 + 221 + 21 + + + + 此处显示chrome.exe的路径 + + + + + + 90 + 50 + 221 + 21 + + + + 此处显示chrome webdriver的路径 + + + + + + 90 + 90 + 221 + 21 + + + + 此处显示输出的zip文件的路径 + + + + + + 10 + 130 + 71 + 51 + + + + 开启浏览器 + + + + + + 90 + 130 + 71 + 51 + + + + 登录 + + + + + + 280 + 130 + 201 + 51 + + + + + true + + + + 下载答题情况 + + + + + + 330 + 10 + 54 + 16 + + + + 起始日期 + + + + + + 330 + 50 + 54 + 16 + + + + 终止日期 + + + + + + 330 + 90 + 71 + 16 + + + + 年级(regex) + + + + + + 390 + 10 + 91 + 20 + + + + yyyymmdd + + + + + + 390 + 50 + 91 + 20 + + + + yyyymmdd + + + + + + 410 + 90 + 71 + 20 + + + + 高[一二] + + + + + + 170 + 130 + 101 + 51 + + + + 获取答题卡列表 + + + + + + 10 + 190 + 471 + 431 + + + + + 答题纸名称 + + + + + 已下载 + + + + + 已更名 + + + + + + +