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