mirror of
https://github.com/cqwu-ehall/cqwu-ehall.git
synced 2024-11-22 02:55:33 +00:00
✨ Support get exam action
This commit is contained in:
parent
e79b7dc429
commit
23407d68ff
@ -1,17 +1,9 @@
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
||||||
|
|
||||||
class ExamRound(str, Enum):
|
|
||||||
Supplementation = "1"
|
|
||||||
""" 开学补缓考 """
|
|
||||||
Scattered = "2"
|
|
||||||
""" 分散考试 """
|
|
||||||
Concentration = "3"
|
|
||||||
""" 集中考试 """
|
|
||||||
|
|
||||||
|
|
||||||
class ScoreSearchType(str, Enum):
|
class ScoreSearchType(str, Enum):
|
||||||
""" 成绩查询类型 """
|
"""成绩查询类型"""
|
||||||
|
|
||||||
All = "1"
|
All = "1"
|
||||||
"""入学以来"""
|
"""入学以来"""
|
||||||
XUENIAN = "2"
|
XUENIAN = "2"
|
||||||
|
@ -6,14 +6,15 @@ class AuthError(CQWUEhallError):
|
|||||||
|
|
||||||
|
|
||||||
class UsernameOrPasswordError(AuthError):
|
class UsernameOrPasswordError(AuthError):
|
||||||
""" 用户名或密码错误 """
|
"""用户名或密码错误"""
|
||||||
|
|
||||||
|
|
||||||
class CookieError(AuthError):
|
class CookieError(AuthError):
|
||||||
""" Cookie 失效 """
|
"""Cookie 失效"""
|
||||||
|
|
||||||
|
|
||||||
class NeedCaptchaError(AuthError):
|
class NeedCaptchaError(AuthError):
|
||||||
""" 需要验证码才能登录 """
|
"""需要验证码才能登录"""
|
||||||
|
|
||||||
def __init__(self, captcha: bytes):
|
def __init__(self, captcha: bytes):
|
||||||
self.captcha = captcha
|
self.captcha = captcha
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
class CQWUEhallError(Exception):
|
class CQWUEhallError(Exception):
|
||||||
"""Base class for exceptions in this module."""
|
"""Base class for exceptions in this module."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
@ -6,8 +6,8 @@ class CQWUWebVPNError(CQWUEhallError):
|
|||||||
|
|
||||||
|
|
||||||
class NoExamData(CQWUWebVPNError):
|
class NoExamData(CQWUWebVPNError):
|
||||||
""" 没有检索到对应的考试记录 """
|
"""没有检索到对应的考试记录"""
|
||||||
|
|
||||||
|
|
||||||
class NoScoreDetailData(CQWUWebVPNError):
|
class NoScoreDetailData(CQWUWebVPNError):
|
||||||
""" 没有检索到对应的成绩明细记录 """
|
"""没有检索到对应的成绩明细记录"""
|
||||||
|
@ -14,6 +14,6 @@ class Auth(
|
|||||||
LoginWithCookie,
|
LoginWithCookie,
|
||||||
LoginWithCookieFile,
|
LoginWithCookieFile,
|
||||||
LoginWithPassword,
|
LoginWithPassword,
|
||||||
Oauth
|
Oauth,
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
@ -10,21 +10,23 @@ class CheckCaptcha:
|
|||||||
username: int = None,
|
username: int = None,
|
||||||
show_qrcode: bool = True,
|
show_qrcode: bool = True,
|
||||||
):
|
):
|
||||||
""" 检查是否需要验证码 """
|
"""检查是否需要验证码"""
|
||||||
username = username or self.username
|
username = username or self.username
|
||||||
params = {
|
params = {
|
||||||
"username": username,
|
"username": username,
|
||||||
"pwdEncrypt2": "pwdEncryptSalt",
|
"pwdEncrypt2": "pwdEncryptSalt",
|
||||||
"_": str(round(time.time() * 1000))
|
"_": str(round(time.time() * 1000)),
|
||||||
}
|
}
|
||||||
url = f"{self.auth_host}/authserver/needCaptcha.html"
|
url = f"{self.auth_host}/authserver/needCaptcha.html"
|
||||||
captcha_html = await self.request.get(url, params=params, follow_redirects=False)
|
captcha_html = await self.request.get(
|
||||||
if captcha_html.text == 'true':
|
url, params=params, follow_redirects=False
|
||||||
params = {
|
)
|
||||||
"ts": str(round(time.time()))
|
if captcha_html.text == "true":
|
||||||
}
|
params = {"ts": str(round(time.time()))}
|
||||||
captcha_url = f"{self.auth_host}/authserver/captcha.html"
|
captcha_url = f"{self.auth_host}/authserver/captcha.html"
|
||||||
res = await self.request.get(captcha_url, params=params, follow_redirects=False)
|
res = await self.request.get(
|
||||||
|
captcha_url, params=params, follow_redirects=False
|
||||||
|
)
|
||||||
if not show_qrcode:
|
if not show_qrcode:
|
||||||
raise NeedCaptchaError(res.content)
|
raise NeedCaptchaError(res.content)
|
||||||
with open("captcha.jpg", mode="wb") as f:
|
with open("captcha.jpg", mode="wb") as f:
|
||||||
|
@ -9,7 +9,7 @@ class Login:
|
|||||||
async def login(
|
async def login(
|
||||||
self: "cqwu.Client",
|
self: "cqwu.Client",
|
||||||
):
|
):
|
||||||
""" 登录 """
|
"""登录"""
|
||||||
with contextlib.suppress(CookieError):
|
with contextlib.suppress(CookieError):
|
||||||
if self.cookie:
|
if self.cookie:
|
||||||
await self.login_with_cookie()
|
await self.login_with_cookie()
|
||||||
|
@ -17,47 +17,51 @@ class LoginWithPassword:
|
|||||||
"""
|
"""
|
||||||
auth_host = auth_host or self.auth_host
|
auth_host = auth_host or self.auth_host
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||||
'Cache-Control': 'max-age=0',
|
"Cache-Control": "max-age=0",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Upgrade-Insecure-Requests': '1',
|
"Upgrade-Insecure-Requests": "1",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63",
|
||||||
}
|
}
|
||||||
html = await self.request.get(f"{auth_host}/authserver/login", headers=headers, follow_redirects=True)
|
html = await self.request.get(
|
||||||
|
f"{auth_host}/authserver/login", headers=headers, follow_redirects=True
|
||||||
|
)
|
||||||
self.cookies.update(html.cookies)
|
self.cookies.update(html.cookies)
|
||||||
tree = etree.HTML(html.text)
|
tree = etree.HTML(html.text)
|
||||||
try:
|
try:
|
||||||
pwd_default_encrypt_salt = tree.xpath('//*[@id="pwdDefaultEncryptSalt"]/@value')[0]
|
pwd_default_encrypt_salt = tree.xpath(
|
||||||
|
'//*[@id="pwdDefaultEncryptSalt"]/@value'
|
||||||
|
)[0]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
if auth_host == self.auth_host:
|
if auth_host == self.auth_host:
|
||||||
self._use_password_login = True # noqa
|
self._use_password_login = True # noqa
|
||||||
self.me = await self.get_me() # noqa
|
self.me = await self.get_me() # noqa
|
||||||
return
|
return
|
||||||
form_data = {
|
form_data = {
|
||||||
'username': str(self.username),
|
"username": str(self.username),
|
||||||
'password': encode_password(self.password, pwd_default_encrypt_salt),
|
"password": encode_password(self.password, pwd_default_encrypt_salt),
|
||||||
'lt': tree.xpath('//*[@id="casLoginForm"]/input[1]/@value')[0],
|
"lt": tree.xpath('//*[@id="casLoginForm"]/input[1]/@value')[0],
|
||||||
'dllt': tree.xpath('//*[@id="casLoginForm"]/input[2]/@value')[0],
|
"dllt": tree.xpath('//*[@id="casLoginForm"]/input[2]/@value')[0],
|
||||||
'execution': tree.xpath('//*[@id="casLoginForm"]/input[3]/@value')[0],
|
"execution": tree.xpath('//*[@id="casLoginForm"]/input[3]/@value')[0],
|
||||||
'_eventId': tree.xpath('//*[@id="casLoginForm"]/input[4]/@value')[0],
|
"_eventId": tree.xpath('//*[@id="casLoginForm"]/input[4]/@value')[0],
|
||||||
'rmShown': tree.xpath('//*[@id="casLoginForm"]/input[5]/@value')[0]
|
"rmShown": tree.xpath('//*[@id="casLoginForm"]/input[5]/@value')[0],
|
||||||
}
|
}
|
||||||
# 是否需要验证码
|
# 是否需要验证码
|
||||||
if not captcha_code:
|
if not captcha_code:
|
||||||
captcha_code = await self.check_captcha(show_qrcode=show_qrcode)
|
captcha_code = await self.check_captcha(show_qrcode=show_qrcode)
|
||||||
if captcha_code:
|
if captcha_code:
|
||||||
form_data['captchaResponse'] = captcha_code
|
form_data["captchaResponse"] = captcha_code
|
||||||
# 登录
|
# 登录
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||||
'Cache-Control': 'max-age=0',
|
"Cache-Control": "max-age=0",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Origin': auth_host,
|
"Origin": auth_host,
|
||||||
'Referer': f'{auth_host}/authserver/login',
|
"Referer": f"{auth_host}/authserver/login",
|
||||||
'Upgrade-Insecure-Requests': '1',
|
"Upgrade-Insecure-Requests": "1",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63",
|
||||||
}
|
}
|
||||||
html = await self.request.post(
|
html = await self.request.post(
|
||||||
f"{auth_host}/authserver/login",
|
f"{auth_host}/authserver/login",
|
||||||
@ -66,7 +70,7 @@ class LoginWithPassword:
|
|||||||
follow_redirects=False,
|
follow_redirects=False,
|
||||||
)
|
)
|
||||||
if auth_host == self.auth_host:
|
if auth_host == self.auth_host:
|
||||||
if 'CASTGC' not in html.cookies.keys():
|
if "CASTGC" not in html.cookies.keys():
|
||||||
raise UsernameOrPasswordError
|
raise UsernameOrPasswordError
|
||||||
self.cookies.update(html.cookies)
|
self.cookies.update(html.cookies)
|
||||||
self._use_password_login = True # noqa
|
self._use_password_login = True # noqa
|
||||||
|
@ -22,6 +22,6 @@ class GetPayBill:
|
|||||||
raise CookieError()
|
raise CookieError()
|
||||||
data = await self.request.post(
|
data = await self.request.post(
|
||||||
"http://218.194.176.214:8382/epay/thirdapp/loadbill.json",
|
"http://218.194.176.214:8382/epay/thirdapp/loadbill.json",
|
||||||
data={"pageno": page_number}
|
data={"pageno": page_number},
|
||||||
)
|
)
|
||||||
return PayBillPage(**data.json())
|
return PayBillPage(**data.json())
|
||||||
|
@ -19,7 +19,10 @@ class Pay(
|
|||||||
html = await self.request.get(url, follow_redirects=False)
|
html = await self.request.get(url, follow_redirects=False)
|
||||||
if html.status_code == 302:
|
if html.status_code == 302:
|
||||||
location = html.headers["location"]
|
location = html.headers["location"]
|
||||||
params = {i.split("=")[0]: i.split("=")[1] for i in location.split("?")[1].split("&")}
|
params = {
|
||||||
|
i.split("=")[0]: i.split("=")[1]
|
||||||
|
for i in location.split("?")[1].split("&")
|
||||||
|
}
|
||||||
self._pay_x_token = params["token"]
|
self._pay_x_token = params["token"]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -18,8 +18,10 @@ class GetPayProjectDetail:
|
|||||||
"""
|
"""
|
||||||
if not self._pay_x_token:
|
if not self._pay_x_token:
|
||||||
await self._oauth_pay()
|
await self._oauth_pay()
|
||||||
url = (f"https://pay.cqwu.edu.cn/api/pay/web/tuitionAndDorm/getTuitionAndDormList/"
|
url = (
|
||||||
f"{self.username}/{project_id}")
|
f"https://pay.cqwu.edu.cn/api/pay/web/tuitionAndDorm/getTuitionAndDormList/"
|
||||||
|
f"{self.username}/{project_id}"
|
||||||
|
)
|
||||||
html = await self.request.get(url, headers=self.pay_headers)
|
html = await self.request.get(url, headers=self.pay_headers)
|
||||||
if html.status_code != 200:
|
if html.status_code != 200:
|
||||||
raise CookieError()
|
raise CookieError()
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
from .get_me import GetMe
|
from .get_me import GetMe
|
||||||
|
|
||||||
|
|
||||||
class Users(
|
class Users(GetMe):
|
||||||
GetMe
|
|
||||||
):
|
|
||||||
pass
|
pass
|
||||||
|
@ -6,7 +6,9 @@ from cqwu import types
|
|||||||
from cqwu.errors.auth import CookieError
|
from cqwu.errors.auth import CookieError
|
||||||
|
|
||||||
|
|
||||||
def get_value_from_soup(soup: BeautifulSoup, attr_id: str) -> Union[type(None), str, int]:
|
def get_value_from_soup(
|
||||||
|
soup: BeautifulSoup, attr_id: str
|
||||||
|
) -> Union[type(None), str, int]:
|
||||||
try:
|
try:
|
||||||
data = soup.find("input", attrs={"id": attr_id})["value"]
|
data = soup.find("input", attrs={"id": attr_id})["value"]
|
||||||
try:
|
try:
|
||||||
@ -53,7 +55,9 @@ class GetMe:
|
|||||||
temp = {key: get_value_from_soup(soup, value) for key, value in data.items()}
|
temp = {key: get_value_from_soup(soup, value) for key, value in data.items()}
|
||||||
temp["password"] = self.password
|
temp["password"] = self.password
|
||||||
try:
|
try:
|
||||||
temp["specialty"] = soup.find_all("input", attrs={"id": "detail_xy"})[1]["value"]
|
temp["specialty"] = soup.find_all("input", attrs={"id": "detail_xy"})[1][
|
||||||
|
"value"
|
||||||
|
]
|
||||||
except (ValueError, TypeError, KeyError, IndexError):
|
except (ValueError, TypeError, KeyError, IndexError):
|
||||||
temp["specialty"] = None
|
temp["specialty"] = None
|
||||||
return types.User(**temp)
|
return types.User(**temp)
|
||||||
|
@ -3,6 +3,7 @@ from httpx import URL
|
|||||||
from .get_calendar import GetCalendar
|
from .get_calendar import GetCalendar
|
||||||
from .get_calendar_change import GetCalendarChange
|
from .get_calendar_change import GetCalendarChange
|
||||||
from .get_exam_calendar import GetExamCalendar
|
from .get_exam_calendar import GetExamCalendar
|
||||||
|
from .get_exam_calendar_action import GetExamCalendarAction
|
||||||
from .get_score_detail import GetScoreDetail
|
from .get_score_detail import GetScoreDetail
|
||||||
from .get_selected_courses import GetSelectedCourses
|
from .get_selected_courses import GetSelectedCourses
|
||||||
from .login_jwmis import LoginJwmis
|
from .login_jwmis import LoginJwmis
|
||||||
@ -13,6 +14,7 @@ class WebVPN(
|
|||||||
GetCalendar,
|
GetCalendar,
|
||||||
GetCalendarChange,
|
GetCalendarChange,
|
||||||
GetExamCalendar,
|
GetExamCalendar,
|
||||||
|
GetExamCalendarAction,
|
||||||
GetScoreDetail,
|
GetScoreDetail,
|
||||||
GetSelectedCourses,
|
GetSelectedCourses,
|
||||||
LoginJwmis,
|
LoginJwmis,
|
||||||
|
@ -14,7 +14,7 @@ class GetCalendar:
|
|||||||
xue_qi: int = None,
|
xue_qi: int = None,
|
||||||
use_model: bool = False,
|
use_model: bool = False,
|
||||||
) -> Union[str, List[AiCourse]]:
|
) -> Union[str, List[AiCourse]]:
|
||||||
""" 获取课程表 """
|
"""获取课程表"""
|
||||||
xue_nian = xue_nian or self.xue_nian
|
xue_nian = xue_nian or self.xue_nian
|
||||||
xue_qi = xue_qi or self.xue_qi
|
xue_qi = xue_qi or self.xue_qi
|
||||||
jw_html = await self.login_jwmis()
|
jw_html = await self.login_jwmis()
|
||||||
@ -24,22 +24,27 @@ class GetCalendar:
|
|||||||
"params": base64.b64encode(f"xn={xue_nian}&xq={xue_qi}".encode()).decode(),
|
"params": base64.b64encode(f"xn={xue_nian}&xq={xue_qi}".encode()).decode(),
|
||||||
}
|
}
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Referer': f'{jw_host}/cqwljw/student/xkjg.wdkb.jsp?menucode=S20301',
|
"Referer": f"{jw_host}/cqwljw/student/xkjg.wdkb.jsp?menucode=S20301",
|
||||||
'Sec-Fetch-Dest': 'iframe',
|
"Sec-Fetch-Dest": "iframe",
|
||||||
'Sec-Fetch-Mode': 'navigate',
|
"Sec-Fetch-Mode": "navigate",
|
||||||
'Sec-Fetch-Site': 'same-origin',
|
"Sec-Fetch-Site": "same-origin",
|
||||||
'Sec-Fetch-User': '?1',
|
"Sec-Fetch-User": "?1",
|
||||||
'Upgrade-Insecure-Requests': '1',
|
"Upgrade-Insecure-Requests": "1",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41",
|
||||||
'sec-ch-ua': '"Microsoft Edge";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
|
"sec-ch-ua": '"Microsoft Edge";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
|
||||||
'sec-ch-ua-mobile': '?0',
|
"sec-ch-ua-mobile": "?0",
|
||||||
'sec-ch-ua-platform': '"Windows"',
|
"sec-ch-ua-platform": '"Windows"',
|
||||||
}
|
}
|
||||||
jw_html = await self.request.get(jw_url, params=params, headers=headers, timeout=60, follow_redirects=True)
|
jw_html = await self.request.get(
|
||||||
jw_html = jw_html.text.replace("""<script type="text/javascript" src="//clientvpn.cqwu.edu.cn/webvpn/bundle.debug.js" charset="utf-8"></script>""", "")
|
jw_url, params=params, headers=headers, timeout=60, follow_redirects=True
|
||||||
|
)
|
||||||
|
jw_html = jw_html.text.replace(
|
||||||
|
"""<script type="text/javascript" src="//clientvpn.cqwu.edu.cn/webvpn/bundle.debug.js" charset="utf-8"></script>""",
|
||||||
|
"",
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
parse_courses(jw_html)
|
parse_courses(jw_html)
|
||||||
if use_model
|
if use_model
|
||||||
|
@ -11,7 +11,7 @@ class GetCalendarChange:
|
|||||||
xue_nian: int = None,
|
xue_nian: int = None,
|
||||||
xue_qi: int = None,
|
xue_qi: int = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
""" 获取课程表 """
|
"""获取课程表"""
|
||||||
xue_nian = xue_nian or self.xue_nian
|
xue_nian = xue_nian or self.xue_nian
|
||||||
xue_qi = xue_qi or self.xue_qi
|
xue_qi = xue_qi or self.xue_qi
|
||||||
jw_html = await self.login_jwmis()
|
jw_html = await self.login_jwmis()
|
||||||
@ -19,50 +19,60 @@ class GetCalendarChange:
|
|||||||
jw_url = f"{jw_host}/cqwljw/student/jxap.jxaptzxx_rpt.jsp"
|
jw_url = f"{jw_host}/cqwljw/student/jxap.jxaptzxx_rpt.jsp"
|
||||||
jw_sg_url = f"{jw_host}/cqwljw/STU_DynamicInitDataAction.do"
|
jw_sg_url = f"{jw_host}/cqwljw/STU_DynamicInitDataAction.do"
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': '*/*',
|
"Accept": "*/*",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Origin': 'https://clientvpn.cqwu.edu.cn',
|
"Origin": "https://clientvpn.cqwu.edu.cn",
|
||||||
'Referer': f'{jw_host}/cqwljw/student/jxap.jxaptzxx.html?menucode=S20302',
|
"Referer": f"{jw_host}/cqwljw/student/jxap.jxaptzxx.html?menucode=S20302",
|
||||||
'Sec-Fetch-Dest': 'empty',
|
"Sec-Fetch-Dest": "empty",
|
||||||
'Sec-Fetch-Mode': 'cors',
|
"Sec-Fetch-Mode": "cors",
|
||||||
'Sec-Fetch-Site': 'same-origin',
|
"Sec-Fetch-Site": "same-origin",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41",
|
||||||
'content-type': 'application/x-www-form-urlencoded',
|
"content-type": "application/x-www-form-urlencoded",
|
||||||
'sec-ch-ua': '"Microsoft Edge";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
|
"sec-ch-ua": '"Microsoft Edge";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
|
||||||
'sec-ch-ua-mobile': '?0',
|
"sec-ch-ua-mobile": "?0",
|
||||||
'sec-ch-ua-platform': '"Windows"',
|
"sec-ch-ua-platform": '"Windows"',
|
||||||
}
|
}
|
||||||
params = {
|
params = {
|
||||||
"classPath": "C73E288D0DEA8D7F772BBD7F8FDC7E66F44C9E3992261989ECBAC5A3D722B306C6354658E0F25121E24CED075326C19885F263F369E5CD668E2EEE7CFB7EB5788F202FC6FD7DB0C96FB6995C1DD96ADE84BE3E72CFFBE9EC74FA044498BD2D21EA0439F9DC625F0EF61B7159924C542D577F814848F27128"
|
"classPath": "C73E288D0DEA8D7F772BBD7F8FDC7E66F44C9E3992261989ECBAC5A3D722B306C6354658E0F25121E24CED075326C19885F263F369E5CD668E2EEE7CFB7EB5788F202FC6FD7DB0C96FB6995C1DD96ADE84BE3E72CFFBE9EC74FA044498BD2D21EA0439F9DC625F0EF61B7159924C542D577F814848F27128"
|
||||||
}
|
}
|
||||||
res = await self.request.post(jw_sg_url, params=params, headers=headers, timeout=60, follow_redirects=True)
|
res = await self.request.post(
|
||||||
|
jw_sg_url, params=params, headers=headers, timeout=60, follow_redirects=True
|
||||||
|
)
|
||||||
data = {
|
data = {
|
||||||
'xh': get_in_middle(res.text, '<xh>', '</xh>'),
|
"xh": get_in_middle(res.text, "<xh>", "</xh>"),
|
||||||
'xn': str(xue_nian),
|
"xn": str(xue_nian),
|
||||||
'xq': str(xue_qi),
|
"xq": str(xue_qi),
|
||||||
'xnxq': f'{xue_nian},{xue_qi}',
|
"xnxq": f"{xue_nian},{xue_qi}",
|
||||||
'menucode_current': 'S20302',
|
"menucode_current": "S20302",
|
||||||
}
|
}
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||||
'Cache-Control': 'max-age=0',
|
"Cache-Control": "max-age=0",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
'Origin': 'https://clientvpn.cqwu.edu.cn',
|
"Origin": "https://clientvpn.cqwu.edu.cn",
|
||||||
'Referer': f'{jw_host}/cqwljw/student/jxap.jxaptzxx.html?menucode=S20302',
|
"Referer": f"{jw_host}/cqwljw/student/jxap.jxaptzxx.html?menucode=S20302",
|
||||||
'Sec-Fetch-Dest': 'iframe',
|
"Sec-Fetch-Dest": "iframe",
|
||||||
'Sec-Fetch-Mode': 'navigate',
|
"Sec-Fetch-Mode": "navigate",
|
||||||
'Sec-Fetch-Site': 'same-origin',
|
"Sec-Fetch-Site": "same-origin",
|
||||||
'Sec-Fetch-User': '?1',
|
"Sec-Fetch-User": "?1",
|
||||||
'Upgrade-Insecure-Requests': '1',
|
"Upgrade-Insecure-Requests": "1",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41",
|
||||||
'sec-ch-ua': '"Microsoft Edge";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
|
"sec-ch-ua": '"Microsoft Edge";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
|
||||||
'sec-ch-ua-mobile': '?0',
|
"sec-ch-ua-mobile": "?0",
|
||||||
'sec-ch-ua-platform': '"Windows"',
|
"sec-ch-ua-platform": '"Windows"',
|
||||||
}
|
}
|
||||||
jw_html = await self.request.post(jw_url, data=data, headers=headers, timeout=60, follow_redirects=True)
|
jw_html = await self.request.post(
|
||||||
jw_html = jw_html.text.replace("""<script type="text/javascript" src="//clientvpn.cqwu.edu.cn/webvpn/bundle.debug.js" charset="utf-8"></script>""", "")
|
jw_url, data=data, headers=headers, timeout=60, follow_redirects=True
|
||||||
jw_html = jw_html.replace("""<script language='javascript' type='text/javascript' src='../js/Print.js'></script>""", "")
|
)
|
||||||
|
jw_html = jw_html.text.replace(
|
||||||
|
"""<script type="text/javascript" src="//clientvpn.cqwu.edu.cn/webvpn/bundle.debug.js" charset="utf-8"></script>""",
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
jw_html = jw_html.replace(
|
||||||
|
"""<script language='javascript' type='text/javascript' src='../js/Print.js'></script>""",
|
||||||
|
"",
|
||||||
|
)
|
||||||
return jw_html.replace("<title></title>", '<meta charset="UTF-8">')
|
return jw_html.replace("<title></title>", '<meta charset="UTF-8">')
|
||||||
|
@ -3,7 +3,6 @@ from typing import Union, List
|
|||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
|
|
||||||
import cqwu
|
import cqwu
|
||||||
from cqwu.enums import ExamRound
|
|
||||||
from cqwu.errors import NoExamData
|
from cqwu.errors import NoExamData
|
||||||
from cqwu.types import AiExam
|
from cqwu.types import AiExam
|
||||||
|
|
||||||
@ -11,56 +10,63 @@ from cqwu.types import AiExam
|
|||||||
class GetExamCalendar:
|
class GetExamCalendar:
|
||||||
async def get_exam_calendar(
|
async def get_exam_calendar(
|
||||||
self: "cqwu.Client",
|
self: "cqwu.Client",
|
||||||
exam_round: Union[str, ExamRound] = ExamRound.Supplementation,
|
exam_round: str = "1",
|
||||||
xue_nian: int = None,
|
xue_nian: int = None,
|
||||||
xue_qi: int = None,
|
xue_qi: int = None,
|
||||||
use_model: bool = False,
|
use_model: bool = False,
|
||||||
) -> Union[str, List[AiExam]]:
|
) -> Union[str, List[AiExam]]:
|
||||||
""" 获取考试安排表 """
|
"""获取考试安排表"""
|
||||||
xue_nian = xue_nian or self.xue_nian
|
xue_nian = xue_nian or self.xue_nian
|
||||||
xue_qi = xue_qi or self.xue_qi
|
xue_qi = xue_qi or self.xue_qi
|
||||||
exam_round = ExamRound(exam_round)
|
|
||||||
jw_html = await self.login_jwmis()
|
jw_html = await self.login_jwmis()
|
||||||
jw_host = self.get_web_vpn_host(jw_html.url, https=True)
|
jw_host = self.get_web_vpn_host(jw_html.url, https=True)
|
||||||
jw_url = f"{jw_host}/cqwljw/student/ksap.ksapb_date.jsp"
|
jw_url = f"{jw_host}/cqwljw/student/ksap.ksapb_date.jsp"
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9,zh-Hans;q=0.8,und;q=0.7,en;q=0.6,zh-Hant;q=0.5,ja;q=0.4',
|
"Accept-Language": "zh-CN,zh;q=0.9,zh-Hans;q=0.8,und;q=0.7,en;q=0.6,zh-Hant;q=0.5,ja;q=0.4",
|
||||||
'Cache-Control': 'no-cache',
|
"Cache-Control": "no-cache",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
'DNT': '1',
|
"DNT": "1",
|
||||||
'Pragma': 'no-cache',
|
"Pragma": "no-cache",
|
||||||
'Referer': f'{jw_host}/cqwljw/student/ksap.ksapb.html?menucode=S20403',
|
"Referer": f"{jw_host}/cqwljw/student/ksap.ksapb.html?menucode=S20403",
|
||||||
'Sec-Fetch-Dest': 'iframe',
|
"Sec-Fetch-Dest": "iframe",
|
||||||
'Sec-Fetch-Mode': 'navigate',
|
"Sec-Fetch-Mode": "navigate",
|
||||||
'Sec-Fetch-Site': 'same-origin',
|
"Sec-Fetch-Site": "same-origin",
|
||||||
'Sec-Fetch-User': '?1',
|
"Sec-Fetch-User": "?1",
|
||||||
'Upgrade-Insecure-Requests': '1',
|
"Upgrade-Insecure-Requests": "1",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
|
||||||
'sec-ch-ua': '"Chromium";v="112", "Not:A-Brand";v="99"',
|
"sec-ch-ua": '"Chromium";v="112", "Not:A-Brand";v="99"',
|
||||||
'sec-ch-ua-mobile': '?0',
|
"sec-ch-ua-mobile": "?0",
|
||||||
'sec-ch-ua-platform': '"Windows"',
|
"sec-ch-ua-platform": '"Windows"',
|
||||||
}
|
}
|
||||||
data = {
|
data = {
|
||||||
'xn': str(xue_nian),
|
"xn": str(xue_nian),
|
||||||
'xq': str(xue_qi),
|
"xq": str(xue_qi),
|
||||||
'title': '',
|
"title": "",
|
||||||
'xnxq': f'{xue_nian}{xue_qi}',
|
"xnxq": f"{xue_nian}{xue_qi}",
|
||||||
'kslc': exam_round.value,
|
"kslc": exam_round,
|
||||||
}
|
}
|
||||||
jw_html = await self.request.post(jw_url, data=data, headers=headers, timeout=60, follow_redirects=True)
|
jw_html = await self.request.post(
|
||||||
|
jw_url, data=data, headers=headers, timeout=60, follow_redirects=True
|
||||||
|
)
|
||||||
if "没有检索到记录!" in jw_html.text:
|
if "没有检索到记录!" in jw_html.text:
|
||||||
raise NoExamData("没有检索到记录!")
|
raise NoExamData("没有检索到记录!")
|
||||||
jw_html = jw_html.text.replace("""<script type="text/javascript" src="//clientvpn.cqwu.edu.cn/webvpn/bundle.debug.js" charset="utf-8"></script>""", "")
|
jw_html = jw_html.text.replace(
|
||||||
jw_html = jw_html.replace("""<script language='javascript' type='text/javascript' src='../js/Print.js'></script>""", "")
|
"""<script type="text/javascript" src="//clientvpn.cqwu.edu.cn/webvpn/bundle.debug.js" charset="utf-8"></script>""",
|
||||||
jw_html = jw_html.replace("charset=GBK", 'charset=UTF-8')
|
"",
|
||||||
|
)
|
||||||
|
jw_html = jw_html.replace(
|
||||||
|
"""<script language='javascript' type='text/javascript' src='../js/Print.js'></script>""",
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
jw_html = jw_html.replace("charset=GBK", "charset=UTF-8")
|
||||||
if not use_model:
|
if not use_model:
|
||||||
return jw_html
|
return jw_html
|
||||||
return parse_html(jw_html, exam_round)
|
return parse_html(jw_html, exam_round)
|
||||||
|
|
||||||
|
|
||||||
def parse_html(html: str, exam_round: ExamRound) -> List[AiExam]:
|
def parse_html(html: str, exam_round: str) -> List[AiExam]:
|
||||||
data: List[AiExam] = []
|
data: List[AiExam] = []
|
||||||
soup = BeautifulSoup(html, "html.parser")
|
soup = BeautifulSoup(html, "html.parser")
|
||||||
trs = soup.find_all("tr")[1:]
|
trs = soup.find_all("tr")[1:]
|
||||||
|
64
cqwu/methods/webvpn/get_exam_calendar_action.py
Normal file
64
cqwu/methods/webvpn/get_exam_calendar_action.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
from json import JSONDecodeError
|
||||||
|
|
||||||
|
import cqwu
|
||||||
|
from cqwu.types.exam import ExamType
|
||||||
|
|
||||||
|
|
||||||
|
class GetExamCalendarAction:
|
||||||
|
async def get_exam_calendar_action(
|
||||||
|
self: "cqwu.Client",
|
||||||
|
xue_nian: int = None,
|
||||||
|
xue_qi: int = None,
|
||||||
|
) -> ExamType:
|
||||||
|
"""获取考试安排可用类型"""
|
||||||
|
xue_nian = xue_nian or self.xue_nian
|
||||||
|
xue_qi = xue_qi or self.xue_qi
|
||||||
|
jw_html = await self.login_jwmis()
|
||||||
|
jw_host = self.get_web_vpn_host(jw_html.url, https=True)
|
||||||
|
jw_url = f"{jw_host}/cqwljw/frame/droplist/getDropLists.action"
|
||||||
|
headers = {
|
||||||
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||||
|
"Accept-Language": "zh-CN,zh;q=0.9,zh-Hans;q=0.8,und;q=0.7,en;q=0.6,zh-Hant;q=0.5,ja;q=0.4",
|
||||||
|
"Cache-Control": "no-cache",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
"DNT": "1",
|
||||||
|
"Pragma": "no-cache",
|
||||||
|
"Referer": f"{jw_host}/cqwljw/student/ksap.ksapb.html?menucode=S20403",
|
||||||
|
"Sec-Fetch-Dest": "iframe",
|
||||||
|
"Sec-Fetch-Mode": "navigate",
|
||||||
|
"Sec-Fetch-Site": "same-origin",
|
||||||
|
"Sec-Fetch-User": "?1",
|
||||||
|
"Upgrade-Insecure-Requests": "1",
|
||||||
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
|
||||||
|
"sec-ch-ua": '"Chromium";v="112", "Not:A-Brand";v="99"',
|
||||||
|
"sec-ch-ua-mobile": "?0",
|
||||||
|
"sec-ch-ua-platform": '"Windows"',
|
||||||
|
}
|
||||||
|
data = {
|
||||||
|
"comboBoxName": "Ms_KSSW_FBKSLC",
|
||||||
|
"paramValue": f"xtdm=jw&zxtdm=7&kgmc=kw_fbksap&xnxq={xue_nian}{xue_qi}",
|
||||||
|
"isYXB": "0",
|
||||||
|
"isCDDW": "0",
|
||||||
|
"isXQ": "0",
|
||||||
|
"isDJKSLB": "0",
|
||||||
|
"isZY": "0",
|
||||||
|
}
|
||||||
|
jw_html = await self.request.post(
|
||||||
|
jw_url, data=data, headers=headers, timeout=60, follow_redirects=True
|
||||||
|
)
|
||||||
|
data = ExamType()
|
||||||
|
try:
|
||||||
|
jw_data = jw_html.json()
|
||||||
|
for i in jw_data:
|
||||||
|
if "开学补缓考" in i["name"]:
|
||||||
|
data.supplementation = i["code"]
|
||||||
|
elif "毕业年级考试" in i["name"]:
|
||||||
|
data.graduate = i["code"]
|
||||||
|
elif "分散考试" in i["name"]:
|
||||||
|
data.scattered = i["code"]
|
||||||
|
elif "集中考试" in i["name"]:
|
||||||
|
data.concentration = i["code"]
|
||||||
|
except JSONDecodeError:
|
||||||
|
pass
|
||||||
|
return data
|
@ -16,7 +16,7 @@ class GetScoreDetail:
|
|||||||
xue_qi: int = None,
|
xue_qi: int = None,
|
||||||
use_model: bool = False,
|
use_model: bool = False,
|
||||||
) -> Union[str, ScoreDetail]:
|
) -> Union[str, ScoreDetail]:
|
||||||
""" 获取学业成绩 """
|
"""获取学业成绩"""
|
||||||
xue_nian = xue_nian or self.xue_nian
|
xue_nian = xue_nian or self.xue_nian
|
||||||
xue_qi = xue_qi or self.xue_qi
|
xue_qi = xue_qi or self.xue_qi
|
||||||
search_type = ScoreSearchType(search_type)
|
search_type = ScoreSearchType(search_type)
|
||||||
@ -24,23 +24,23 @@ class GetScoreDetail:
|
|||||||
jw_host = self.get_web_vpn_host(jw_html.url, https=True)
|
jw_host = self.get_web_vpn_host(jw_html.url, https=True)
|
||||||
jw_url = f"{jw_host}/cqwljw/student/xscj.stuckcj_data.jsp"
|
jw_url = f"{jw_host}/cqwljw/student/xscj.stuckcj_data.jsp"
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9,zh-Hans;q=0.8,und;q=0.7,en;q=0.6,zh-Hant;q=0.5,ja;q=0.4',
|
"Accept-Language": "zh-CN,zh;q=0.9,zh-Hans;q=0.8,und;q=0.7,en;q=0.6,zh-Hant;q=0.5,ja;q=0.4",
|
||||||
'Cache-Control': 'no-cache',
|
"Cache-Control": "no-cache",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Content-Type': 'application/x-www-form-urlencoded',
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
'DNT': '1',
|
"DNT": "1",
|
||||||
'Pragma': 'no-cache',
|
"Pragma": "no-cache",
|
||||||
'Referer': f'{jw_host}/cqwljw/student/ksap.ksapb.html?menucode=S20403',
|
"Referer": f"{jw_host}/cqwljw/student/ksap.ksapb.html?menucode=S20403",
|
||||||
'Sec-Fetch-Dest': 'iframe',
|
"Sec-Fetch-Dest": "iframe",
|
||||||
'Sec-Fetch-Mode': 'navigate',
|
"Sec-Fetch-Mode": "navigate",
|
||||||
'Sec-Fetch-Site': 'same-origin',
|
"Sec-Fetch-Site": "same-origin",
|
||||||
'Sec-Fetch-User': '?1',
|
"Sec-Fetch-User": "?1",
|
||||||
'Upgrade-Insecure-Requests': '1',
|
"Upgrade-Insecure-Requests": "1",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36",
|
||||||
'sec-ch-ua': '"Chromium";v="112", "Not:A-Brand";v="99"',
|
"sec-ch-ua": '"Chromium";v="112", "Not:A-Brand";v="99"',
|
||||||
'sec-ch-ua-mobile': '?0',
|
"sec-ch-ua-mobile": "?0",
|
||||||
'sec-ch-ua-platform': '"Windows"',
|
"sec-ch-ua-platform": '"Windows"',
|
||||||
}
|
}
|
||||||
data = {
|
data = {
|
||||||
"sjxz": f"sjxz{search_type.value}",
|
"sjxz": f"sjxz{search_type.value}",
|
||||||
@ -50,7 +50,7 @@ class GetScoreDetail:
|
|||||||
"btnExport": "%B5%BC%B3%F6",
|
"btnExport": "%B5%BC%B3%F6",
|
||||||
"rxnj": str(xue_nian),
|
"rxnj": str(xue_nian),
|
||||||
"xn": str(xue_nian),
|
"xn": str(xue_nian),
|
||||||
'xn1': str(xue_nian + 1),
|
"xn1": str(xue_nian + 1),
|
||||||
"xq": str(xue_qi),
|
"xq": str(xue_qi),
|
||||||
"ysyxS": "on",
|
"ysyxS": "on",
|
||||||
"sjxzS": "on",
|
"sjxzS": "on",
|
||||||
@ -58,12 +58,20 @@ class GetScoreDetail:
|
|||||||
"fxC": "on",
|
"fxC": "on",
|
||||||
"xsjd": "1",
|
"xsjd": "1",
|
||||||
}
|
}
|
||||||
jw_html = await self.request.post(jw_url, data=data, headers=headers, timeout=60, follow_redirects=True)
|
jw_html = await self.request.post(
|
||||||
|
jw_url, data=data, headers=headers, timeout=60, follow_redirects=True
|
||||||
|
)
|
||||||
if "没有检索到记录!" in jw_html.text:
|
if "没有检索到记录!" in jw_html.text:
|
||||||
raise NoScoreDetailData("没有检索到记录!")
|
raise NoScoreDetailData("没有检索到记录!")
|
||||||
jw_html = jw_html.text.replace("""<script type="text/javascript" src="//clientvpn.cqwu.edu.cn/webvpn/bundle.debug.js" charset="utf-8"></script>""", "")
|
jw_html = jw_html.text.replace(
|
||||||
jw_html = jw_html.replace("""<script language='javascript' type='text/javascript' src='../js/Print.js'></script>""", "")
|
"""<script type="text/javascript" src="//clientvpn.cqwu.edu.cn/webvpn/bundle.debug.js" charset="utf-8"></script>""",
|
||||||
jw_html = jw_html.replace("charset=GBK", 'charset=UTF-8')
|
"",
|
||||||
|
)
|
||||||
|
jw_html = jw_html.replace(
|
||||||
|
"""<script language='javascript' type='text/javascript' src='../js/Print.js'></script>""",
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
jw_html = jw_html.replace("charset=GBK", "charset=UTF-8")
|
||||||
if not use_model:
|
if not use_model:
|
||||||
return jw_html
|
return jw_html
|
||||||
return parse_html(jw_html)
|
return parse_html(jw_html)
|
||||||
|
@ -12,27 +12,32 @@ class GetSelectedCourses:
|
|||||||
self: "cqwu.Client",
|
self: "cqwu.Client",
|
||||||
use_model: bool = False,
|
use_model: bool = False,
|
||||||
) -> Union[str, List[AiCourse]]:
|
) -> Union[str, List[AiCourse]]:
|
||||||
""" 获取选课结果 """
|
"""获取选课结果"""
|
||||||
jw_html = await self.login_jwmis()
|
jw_html = await self.login_jwmis()
|
||||||
jw_host = self.get_web_vpn_host(jw_html.url)
|
jw_host = self.get_web_vpn_host(jw_html.url)
|
||||||
jw_url = f"{jw_host}/cqwljw/student/wsxk.zxjg.jsp"
|
jw_url = f"{jw_host}/cqwljw/student/wsxk.zxjg.jsp"
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Referer': f'{jw_host}/cqwljw/frame/homes.html',
|
"Referer": f"{jw_host}/cqwljw/frame/homes.html",
|
||||||
'Sec-Fetch-Dest': 'iframe',
|
"Sec-Fetch-Dest": "iframe",
|
||||||
'Sec-Fetch-Mode': 'navigate',
|
"Sec-Fetch-Mode": "navigate",
|
||||||
'Sec-Fetch-Site': 'same-origin',
|
"Sec-Fetch-Site": "same-origin",
|
||||||
'Sec-Fetch-User': '?1',
|
"Sec-Fetch-User": "?1",
|
||||||
'Upgrade-Insecure-Requests': '1',
|
"Upgrade-Insecure-Requests": "1",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.41",
|
||||||
'sec-ch-ua': '"Microsoft Edge";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
|
"sec-ch-ua": '"Microsoft Edge";v="111", "Not(A:Brand";v="8", "Chromium";v="111"',
|
||||||
'sec-ch-ua-mobile': '?0',
|
"sec-ch-ua-mobile": "?0",
|
||||||
'sec-ch-ua-platform': '"Windows"',
|
"sec-ch-ua-platform": '"Windows"',
|
||||||
}
|
}
|
||||||
jw_html = await self.request.get(jw_url, headers=headers, timeout=60, follow_redirects=True)
|
jw_html = await self.request.get(
|
||||||
jw_html = jw_html.text.replace("""<script type="text/javascript" src="//clientvpn.cqwu.edu.cn/webvpn/bundle.debug.js" charset="utf-8"></script>""", "")
|
jw_url, headers=headers, timeout=60, follow_redirects=True
|
||||||
|
)
|
||||||
|
jw_html = jw_html.text.replace(
|
||||||
|
"""<script type="text/javascript" src="//clientvpn.cqwu.edu.cn/webvpn/bundle.debug.js" charset="utf-8"></script>""",
|
||||||
|
"",
|
||||||
|
)
|
||||||
return (
|
return (
|
||||||
parse_courses(jw_html)
|
parse_courses(jw_html)
|
||||||
if use_model
|
if use_model
|
||||||
@ -57,7 +62,9 @@ def parse_courses(jw_html: str) -> List[AiCourse]:
|
|||||||
for calendar in calendars:
|
for calendar in calendars:
|
||||||
text = (BeautifulSoup(calendar, "lxml")).text.strip()
|
text = (BeautifulSoup(calendar, "lxml")).text.strip()
|
||||||
try:
|
try:
|
||||||
position, weeks, day, start_num, sections = parse_weeks_and_sections(text)
|
position, weeks, day, start_num, sections = parse_weeks_and_sections(
|
||||||
|
text
|
||||||
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
item = AiCourse(
|
item = AiCourse(
|
||||||
|
@ -8,9 +8,10 @@ class LoginJwmis:
|
|||||||
async def login_jwmis(
|
async def login_jwmis(
|
||||||
self: "cqwu.Client",
|
self: "cqwu.Client",
|
||||||
) -> Response:
|
) -> Response:
|
||||||
""" 登录教学管理平台 """
|
"""登录教学管理平台"""
|
||||||
jw_html = await self.request.get(
|
jw_html = await self.request.get(
|
||||||
f"{self.web_ehall_path}/appShow?appId=5299144291521305", follow_redirects=True
|
f"{self.web_ehall_path}/appShow?appId=5299144291521305",
|
||||||
|
follow_redirects=True,
|
||||||
)
|
)
|
||||||
if "教学管理服务平台" not in jw_html.text:
|
if "教学管理服务平台" not in jw_html.text:
|
||||||
raise CookieError
|
raise CookieError
|
||||||
|
@ -13,7 +13,9 @@ class LoginWebVPN:
|
|||||||
url = "https://webvpn.cqwu.edu.cn"
|
url = "https://webvpn.cqwu.edu.cn"
|
||||||
ehall_html = await self.request.get(url, follow_redirects=True)
|
ehall_html = await self.request.get(url, follow_redirects=True)
|
||||||
self.web_ehall_path = self.get_web_vpn_host(ehall_html.url) # noqa
|
self.web_ehall_path = self.get_web_vpn_host(ehall_html.url) # noqa
|
||||||
await self.oauth("https://authserver.cqwu.edu.cn/authserver/login?service=https://clientvpn.cqwu.edu.cn/enlink/api/client/callback/cas")
|
await self.oauth(
|
||||||
|
"https://authserver.cqwu.edu.cn/authserver/login?service=https://clientvpn.cqwu.edu.cn/enlink/api/client/callback/cas"
|
||||||
|
)
|
||||||
auth_html = await self.request.get(
|
auth_html = await self.request.get(
|
||||||
f"{self.web_ehall_path}/login", follow_redirects=True
|
f"{self.web_ehall_path}/login", follow_redirects=True
|
||||||
)
|
)
|
||||||
|
@ -22,15 +22,15 @@ class XG(
|
|||||||
raise CookieError()
|
raise CookieError()
|
||||||
url = "http://xg.cqwu.edu.cn/xsfw/sys/swpubapp/indexmenu/getAppConfig.do"
|
url = "http://xg.cqwu.edu.cn/xsfw/sys/swpubapp/indexmenu/getAppConfig.do"
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': '*/*',
|
"Accept": "*/*",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,hu;q=0.5',
|
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,hu;q=0.5",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Referer': 'http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/*default/index.do',
|
"Referer": "http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/*default/index.do",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.51',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.51",
|
||||||
}
|
}
|
||||||
params = {
|
params = {
|
||||||
'appId': '5275772372599202',
|
"appId": "5275772372599202",
|
||||||
'appName': 'zhcptybbapp',
|
"appName": "zhcptybbapp",
|
||||||
'v': '021534151969418724',
|
"v": "021534151969418724",
|
||||||
}
|
}
|
||||||
await self.request.get(url, headers=headers, params=params)
|
await self.request.get(url, headers=headers, params=params)
|
||||||
|
@ -13,33 +13,33 @@ class GetCP:
|
|||||||
year: int = None,
|
year: int = None,
|
||||||
semester: int = None,
|
semester: int = None,
|
||||||
) -> CP:
|
) -> CP:
|
||||||
""" 获取综合测评结果 """
|
"""获取综合测评结果"""
|
||||||
xue_nian = year or self.xue_nian
|
xue_nian = year or self.xue_nian
|
||||||
xue_qi = semester or self.xue_qi
|
xue_qi = semester or self.xue_qi
|
||||||
await self.oauth_xg()
|
await self.oauth_xg()
|
||||||
url = "http://xg.cqwu.edu.cn/xsfw/sys/emapcomponent/imexport/export.do"
|
url = "http://xg.cqwu.edu.cn/xsfw/sys/emapcomponent/imexport/export.do"
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,hu;q=0.5',
|
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,hu;q=0.5",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||||
'Origin': 'http://xg.cqwu.edu.cn',
|
"Origin": "http://xg.cqwu.edu.cn",
|
||||||
'Referer': 'http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/*default/index.do',
|
"Referer": "http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/*default/index.do",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.51',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.51",
|
||||||
'X-Requested-With': 'XMLHttpRequest',
|
"X-Requested-With": "XMLHttpRequest",
|
||||||
}
|
}
|
||||||
data = {
|
data = {
|
||||||
'app': 'zhcptybbapp',
|
"app": "zhcptybbapp",
|
||||||
'contextPath': 'http://xg.cqwu.edu.cn/xsfw',
|
"contextPath": "http://xg.cqwu.edu.cn/xsfw",
|
||||||
'module': 'modules',
|
"module": "modules",
|
||||||
'page': 'cpjgcx',
|
"page": "cpjgcx",
|
||||||
'action': 'cpjgcxbgdz',
|
"action": "cpjgcxbgdz",
|
||||||
'containerId': 'cpjg_grid',
|
"containerId": "cpjg_grid",
|
||||||
'CPXN': str(xue_nian),
|
"CPXN": str(xue_nian),
|
||||||
'CPXQ': str(xue_qi),
|
"CPXQ": str(xue_qi),
|
||||||
'filename': '综合测评结果',
|
"filename": "综合测评结果",
|
||||||
'colnames': 'XH,XM,CPXN,CPXQ,DWDM,DZ_ZYFX,BJDM,ZCJ,BJPM,BJRS,ZYNJPM,ZYNJRS,FS1,FS10,FS11,FS12,'
|
"colnames": "XH,XM,CPXN,CPXQ,DWDM,DZ_ZYFX,BJDM,ZCJ,BJPM,BJRS,ZYNJPM,ZYNJRS,FS1,FS10,FS11,FS12,"
|
||||||
'XZNJ,DZ_BJPM,DZ_ZYPM',
|
"XZNJ,DZ_BJPM,DZ_ZYPM",
|
||||||
}
|
}
|
||||||
html = await self.request.post(url, headers=headers, data=data)
|
html = await self.request.post(url, headers=headers, data=data)
|
||||||
if html.status_code != 200:
|
if html.status_code != 200:
|
||||||
|
@ -12,25 +12,27 @@ class GetPublicCP:
|
|||||||
page_number: int = 1,
|
page_number: int = 1,
|
||||||
total: bool = True,
|
total: bool = True,
|
||||||
) -> List[PublicCPRaw]:
|
) -> List[PublicCPRaw]:
|
||||||
""" 获取综合测评公示结果 """
|
"""获取综合测评公示结果"""
|
||||||
await self.oauth_xg()
|
await self.oauth_xg()
|
||||||
|
|
||||||
async def get_public_cp_raw(page_size_: int, page_number_: int) -> CPGS:
|
async def get_public_cp_raw(page_size_: int, page_number_: int) -> CPGS:
|
||||||
url = "http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/modules/cpgs/cpgs_cpgsbg.do"
|
url = (
|
||||||
|
"http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/modules/cpgs/cpgs_cpgsbg.do"
|
||||||
|
)
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,hu;q=0.5',
|
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6,hu;q=0.5",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||||
'Origin': 'http://xg.cqwu.edu.cn',
|
"Origin": "http://xg.cqwu.edu.cn",
|
||||||
'Referer': 'http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/*default/index.do',
|
"Referer": "http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/*default/index.do",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.51',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/111.0.0.0 Safari/537.36 Edg/111.0.1661.51",
|
||||||
'X-Requested-With': 'XMLHttpRequest',
|
"X-Requested-With": "XMLHttpRequest",
|
||||||
}
|
}
|
||||||
data = {
|
data = {
|
||||||
'querySetting': '[]',
|
"querySetting": "[]",
|
||||||
'pageSize': str(page_size_),
|
"pageSize": str(page_size_),
|
||||||
'pageNumber': str(page_number_),
|
"pageNumber": str(page_number_),
|
||||||
}
|
}
|
||||||
html = await self.request.post(url, headers=headers, data=data)
|
html = await self.request.post(url, headers=headers, data=data)
|
||||||
if html.status_code != 200:
|
if html.status_code != 200:
|
||||||
@ -59,7 +61,10 @@ class GetPublicCP:
|
|||||||
return_datas.extend(html_raw_datas.rows)
|
return_datas.extend(html_raw_datas.rows)
|
||||||
if html_raw_datas.totalSize == 0:
|
if html_raw_datas.totalSize == 0:
|
||||||
break
|
break
|
||||||
elif html_raw_datas.pageNumber * html_raw_datas.pageSize >= html_raw_datas.totalSize:
|
elif (
|
||||||
|
html_raw_datas.pageNumber * html_raw_datas.pageSize
|
||||||
|
>= html_raw_datas.totalSize
|
||||||
|
):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
page_number += 1
|
page_number += 1
|
||||||
|
@ -7,9 +7,9 @@ from cqwu import types
|
|||||||
|
|
||||||
class GetScore:
|
class GetScore:
|
||||||
async def get_score(
|
async def get_score(
|
||||||
self: "cqwu.Client",
|
self: "cqwu.Client",
|
||||||
year: int = None,
|
year: int = None,
|
||||||
semester: int = None,
|
semester: int = None,
|
||||||
) -> List["types.Score"]:
|
) -> List["types.Score"]:
|
||||||
"""
|
"""
|
||||||
获取期末成绩
|
获取期末成绩
|
||||||
@ -20,16 +20,18 @@ class GetScore:
|
|||||||
year = year or self.xue_nian
|
year = year or self.xue_nian
|
||||||
semester = semester or (self.xue_qi + 1)
|
semester = semester or (self.xue_qi + 1)
|
||||||
await self.oauth_xg()
|
await self.oauth_xg()
|
||||||
query_url = "http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/modules/cjcx/cjcxbgdz.do"
|
query_url = (
|
||||||
|
"http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/modules/cjcx/cjcxbgdz.do"
|
||||||
|
)
|
||||||
headers = {
|
headers = {
|
||||||
'Accept': 'application/json, text/javascript, */*; q=0.01',
|
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
"Accept-Language": "zh-CN,zh;q=0.9",
|
||||||
'Connection': 'keep-alive',
|
"Connection": "keep-alive",
|
||||||
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
|
||||||
'Origin': 'http://xg.cqwu.edu.cn',
|
"Origin": "http://xg.cqwu.edu.cn",
|
||||||
'Referer': 'http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/*default/index.do',
|
"Referer": "http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/*default/index.do",
|
||||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63',
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.63",
|
||||||
'X-Requested-With': 'XMLHttpRequest',
|
"X-Requested-With": "XMLHttpRequest",
|
||||||
}
|
}
|
||||||
query_data = [
|
query_data = [
|
||||||
{
|
{
|
||||||
@ -47,12 +49,12 @@ class GetScore:
|
|||||||
"builderList": "cbl_m_List",
|
"builderList": "cbl_m_List",
|
||||||
"builder": "m_value_equal",
|
"builder": "m_value_equal",
|
||||||
"value": str(semester),
|
"value": str(semester),
|
||||||
}
|
},
|
||||||
]
|
]
|
||||||
data = {
|
data = {
|
||||||
'querySetting': json.dumps(query_data),
|
"querySetting": json.dumps(query_data),
|
||||||
'pageSize': '100',
|
"pageSize": "100",
|
||||||
'pageNumber': '1',
|
"pageNumber": "1",
|
||||||
}
|
}
|
||||||
html = await self.request.post(query_url, headers=headers, data=data)
|
html = await self.request.post(query_url, headers=headers, data=data)
|
||||||
data = [types.Score(**i) for i in html.json()["datas"]["cjcxbgdz"]["rows"]]
|
data = [types.Score(**i) for i in html.json()["datas"]["cjcxbgdz"]["rows"]]
|
||||||
|
@ -4,5 +4,10 @@ from .epay import PayBill, PayBillPage
|
|||||||
from .exam import AiExam
|
from .exam import AiExam
|
||||||
from .pay import PayProject, PayProjectDetail, PayUser
|
from .pay import PayProject, PayProjectDetail, PayUser
|
||||||
from .score import Score
|
from .score import Score
|
||||||
from .score_detail import ScoreDetail, ScoreDetailInfo, ScoreDetailCourse, ScoreDetailTotal
|
from .score_detail import (
|
||||||
|
ScoreDetail,
|
||||||
|
ScoreDetailInfo,
|
||||||
|
ScoreDetailCourse,
|
||||||
|
ScoreDetailTotal,
|
||||||
|
)
|
||||||
from .user import User
|
from .user import User
|
||||||
|
@ -29,5 +29,11 @@ class AiCourse(BaseModel):
|
|||||||
"weeks": ",".join(list(map(str, self.weeks))),
|
"weeks": ",".join(list(map(str, self.weeks))),
|
||||||
"day": self.day,
|
"day": self.day,
|
||||||
"style": "",
|
"style": "",
|
||||||
"sections": ",".join(list(map(str, list(range(self.start_num, self.start_num + self.sections)))))
|
"sections": ",".join(
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
str, list(range(self.start_num, self.start_num + self.sections))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
@ -40,77 +40,77 @@ class PublicCPRaw(BaseModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def id(self) -> int:
|
def id(self) -> int:
|
||||||
""" 学号 """
|
"""学号"""
|
||||||
return int(self.XH)
|
return int(self.XH)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
""" 姓名 """
|
"""姓名"""
|
||||||
return self.XM
|
return self.XM
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def yuan_xi(self) -> str:
|
def yuan_xi(self) -> str:
|
||||||
""" 院系 """
|
"""院系"""
|
||||||
return self.DWDM_DISPLAY
|
return self.DWDM_DISPLAY
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def zhuan_ye(self) -> str:
|
def zhuan_ye(self) -> str:
|
||||||
""" 专业 """
|
"""专业"""
|
||||||
return self.ZYDM_DISPLAY
|
return self.ZYDM_DISPLAY
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def class_name(self) -> str:
|
def class_name(self) -> str:
|
||||||
""" 班级 """
|
"""班级"""
|
||||||
return self.BJDM_DISPLAY
|
return self.BJDM_DISPLAY
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def total_score(self) -> float:
|
def total_score(self) -> float:
|
||||||
""" 总成绩 """
|
"""总成绩"""
|
||||||
return float(self.ZCJ)
|
return float(self.ZCJ)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def class_rank(self) -> int:
|
def class_rank(self) -> int:
|
||||||
""" 班级排名 """
|
"""班级排名"""
|
||||||
return int(self.BJPM)
|
return int(self.BJPM)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def grade_rank(self) -> int:
|
def grade_rank(self) -> int:
|
||||||
""" 专业年级排名 """
|
"""专业年级排名"""
|
||||||
return int(self.ZYNJPM)
|
return int(self.ZYNJPM)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dysz(self) -> float:
|
def dysz(self) -> float:
|
||||||
""" 德育素质分 """
|
"""德育素质分"""
|
||||||
return float(self.FS1)
|
return float(self.FS1)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def zysz(self) -> float:
|
def zysz(self) -> float:
|
||||||
""" 智育素质测评 """
|
"""智育素质测评"""
|
||||||
return float(self.FS10)
|
return float(self.FS10)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cxsz(self) -> float:
|
def cxsz(self) -> float:
|
||||||
""" 创新素质测评 """
|
"""创新素质测评"""
|
||||||
return float(self.FS11)
|
return float(self.FS11)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wtsz(self) -> float:
|
def wtsz(self) -> float:
|
||||||
""" 文体素质 """
|
"""文体素质"""
|
||||||
return float(self.FS12)
|
return float(self.FS12)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def dysz_raw(self) -> float:
|
def dysz_raw(self) -> float:
|
||||||
""" 德育原始成绩 """
|
"""德育原始成绩"""
|
||||||
return float(self.DYYSCJ)
|
return float(self.DYYSCJ)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def wtsz_raw(self) -> float:
|
def wtsz_raw(self) -> float:
|
||||||
""" 文体原始成绩 """
|
"""文体原始成绩"""
|
||||||
return float(self.WTYSCJ)
|
return float(self.WTYSCJ)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def cxsz_raw(self) -> float:
|
def cxsz_raw(self) -> float:
|
||||||
""" 创新原始成绩 """
|
"""创新原始成绩"""
|
||||||
return float(self.CXYSCJ)
|
return float(self.CXYSCJ)
|
||||||
|
|
||||||
|
|
||||||
|
@ -3,7 +3,28 @@ from typing import Tuple
|
|||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
|
||||||
from cqwu.enums import ExamRound
|
|
||||||
|
class ExamType:
|
||||||
|
supplementation: str
|
||||||
|
""" 开学补缓考 """
|
||||||
|
graduate: str
|
||||||
|
""" 毕业年级考试 """
|
||||||
|
scattered: str
|
||||||
|
""" 分散考试 """
|
||||||
|
concentration: str
|
||||||
|
""" 集中考试 """
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
supplementation: str = "",
|
||||||
|
graduate: str = "",
|
||||||
|
scattered: str = "",
|
||||||
|
concentration: str = "",
|
||||||
|
):
|
||||||
|
self.supplementation = supplementation
|
||||||
|
self.graduate = graduate
|
||||||
|
self.scattered = scattered
|
||||||
|
self.concentration = concentration
|
||||||
|
|
||||||
|
|
||||||
class AiExam(BaseModel):
|
class AiExam(BaseModel):
|
||||||
@ -17,25 +38,33 @@ class AiExam(BaseModel):
|
|||||||
""" 考试地点 """
|
""" 考试地点 """
|
||||||
seat: str
|
seat: str
|
||||||
""" 座位号 """
|
""" 座位号 """
|
||||||
exam_round: ExamRound
|
exam_round: str
|
||||||
""" 考试轮次 """
|
""" 考试轮次 """
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name_no_id(self) -> str:
|
def name_no_id(self) -> str:
|
||||||
""" 获取课程名称(去除课程编号) """
|
"""获取课程名称(去除课程编号)"""
|
||||||
return self.name.split("]")[-1]
|
return self.name.split("]")[-1]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def days_left(self) -> int:
|
def days_left(self) -> int:
|
||||||
""" 获取距离考试的天数 """
|
"""获取距离考试的天数"""
|
||||||
return (self.get_time()[0] - datetime.datetime.now()).days
|
return (self.get_time()[0] - datetime.datetime.now()).days
|
||||||
|
|
||||||
def get_time(self) -> Tuple[datetime.datetime, datetime.datetime]:
|
def get_time(self) -> Tuple[datetime.datetime, datetime.datetime]:
|
||||||
""" 获取格式化后的考试时间 """
|
"""获取格式化后的考试时间"""
|
||||||
# 2023-06-25(18周 星期日)09:00-11:00
|
# 2023-06-25(18周 星期日)09:00-11:00
|
||||||
day = datetime.datetime.strptime(self.time.split("(")[0], "%Y-%m-%d")
|
day = datetime.datetime.strptime(self.time.split("(")[0], "%Y-%m-%d")
|
||||||
start_time = datetime.datetime.strptime(self.time.split(")")[1].split("-")[0], "%H:%M")
|
start_time = datetime.datetime.strptime(
|
||||||
start_time = datetime.datetime(day.year, day.month, day.day, start_time.hour, start_time.minute)
|
self.time.split(")")[1].split("-")[0], "%H:%M"
|
||||||
end_time = datetime.datetime.strptime(self.time.split(")")[1].split("-")[1], "%H:%M")
|
)
|
||||||
end_time = datetime.datetime(day.year, day.month, day.day, end_time.hour, end_time.minute)
|
start_time = datetime.datetime(
|
||||||
|
day.year, day.month, day.day, start_time.hour, start_time.minute
|
||||||
|
)
|
||||||
|
end_time = datetime.datetime.strptime(
|
||||||
|
self.time.split(")")[1].split("-")[1], "%H:%M"
|
||||||
|
)
|
||||||
|
end_time = datetime.datetime(
|
||||||
|
day.year, day.month, day.day, end_time.hour, end_time.minute
|
||||||
|
)
|
||||||
return start_time, end_time
|
return start_time, end_time
|
||||||
|
@ -2,7 +2,8 @@ from pydantic import BaseModel
|
|||||||
|
|
||||||
|
|
||||||
class Score(BaseModel):
|
class Score(BaseModel):
|
||||||
""" 成绩类 """
|
"""成绩类"""
|
||||||
|
|
||||||
KCMC: str
|
KCMC: str
|
||||||
XF: float
|
XF: float
|
||||||
ZCJ: float
|
ZCJ: float
|
||||||
@ -14,30 +15,30 @@ class Score(BaseModel):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self) -> str:
|
def name(self) -> str:
|
||||||
""" 课程名称 """
|
"""课程名称"""
|
||||||
return self.KCMC
|
return self.KCMC
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def credit(self) -> float:
|
def credit(self) -> float:
|
||||||
""" 学分 """
|
"""学分"""
|
||||||
return self.XF
|
return self.XF
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def score(self) -> float:
|
def score(self) -> float:
|
||||||
""" 成绩 """
|
"""成绩"""
|
||||||
return self.ZCJ
|
return self.ZCJ
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def grade_point(self) -> float:
|
def grade_point(self) -> float:
|
||||||
""" 绩点 """
|
"""绩点"""
|
||||||
return float(self.JD)
|
return float(self.JD)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def year(self) -> int:
|
def year(self) -> int:
|
||||||
""" 学年 """
|
"""学年"""
|
||||||
return int(self.XN)
|
return int(self.XN)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def semester(self) -> int:
|
def semester(self) -> int:
|
||||||
""" 学期 """
|
"""学期"""
|
||||||
return int(self.XQ)
|
return int(self.XQ)
|
||||||
|
4
setup.py
4
setup.py
@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|||||||
|
|
||||||
setuptools.setup(
|
setuptools.setup(
|
||||||
name="cqwu", # 用自己的名替换其中的YOUR_USERNAME_
|
name="cqwu", # 用自己的名替换其中的YOUR_USERNAME_
|
||||||
version="0.0.17", # 包版本号,便于维护版本
|
version="0.0.18", # 包版本号,便于维护版本
|
||||||
author="omg-xtao", # 作者,可以写自己的姓名
|
author="omg-xtao", # 作者,可以写自己的姓名
|
||||||
author_email="xtao@xtaolink.cn", # 作者联系方式,可写自己的邮箱地址
|
author_email="xtao@xtaolink.cn", # 作者联系方式,可写自己的邮箱地址
|
||||||
description="A cqwu ehall client.", # 包的简述
|
description="A cqwu ehall client.", # 包的简述
|
||||||
@ -18,7 +18,7 @@ setuptools.setup(
|
|||||||
"License :: OSI Approved :: MIT License",
|
"License :: OSI Approved :: MIT License",
|
||||||
"Operating System :: OS Independent",
|
"Operating System :: OS Independent",
|
||||||
],
|
],
|
||||||
python_requires='>=3.8', # 对python的最低版本要求
|
python_requires=">=3.8", # 对python的最低版本要求
|
||||||
install_requires=[
|
install_requires=[
|
||||||
"httpx",
|
"httpx",
|
||||||
"lxml",
|
"lxml",
|
||||||
|
Loading…
Reference in New Issue
Block a user