mirror of
https://github.com/cqwu-ehall/cqwu-ehall.git
synced 2024-11-22 02:55:33 +00:00
✨ Support get calendar
Co-authored-by: brian <brian@xtaolabs.com>
This commit is contained in:
parent
e2a43b1c5d
commit
ca794ea619
@ -15,22 +15,21 @@ class Client(Methods):
|
||||
password: str = None,
|
||||
cookie: str = None,
|
||||
cookie_file_path: str = "cookie.txt",
|
||||
client_vpn: bool = False,
|
||||
):
|
||||
self.username = username
|
||||
self.password = password
|
||||
self.cookie = cookie
|
||||
self.cookie_file_path = cookie_file_path
|
||||
if client_vpn:
|
||||
self.host = "https://clientvpn.cqwu.edu.cn:10443/http/webvpn507e990968de07079b0f10d16c49bdb1cb8d3ca3a4d14f557999e92cbdf19fcd"
|
||||
self.auth_host = self.host
|
||||
else:
|
||||
self.host = "http://ehall.cqwu.edu.cn"
|
||||
self.auth_host = "http://authserver.cqwu.edu.cn"
|
||||
self.web_ehall_path = ""
|
||||
self.cookies = Cookies()
|
||||
self.request = AsyncClient()
|
||||
self.loop = asyncio.get_event_loop()
|
||||
self.me: Optional[User] = None
|
||||
self._use_password_login = False
|
||||
self.xue_nian = 2022 # 学年
|
||||
self.xue_qi = 1 # 学期 0 为第一学期, 1 为第二学期
|
||||
|
||||
@staticmethod
|
||||
def get_input(word: str = "", is_int: bool = False):
|
||||
|
@ -1,6 +1,7 @@
|
||||
from .auth import Auth
|
||||
from .epay import EPay
|
||||
from .users import Users
|
||||
from .webvpn import WebVPN
|
||||
from .xg import XG
|
||||
|
||||
|
||||
@ -8,6 +9,7 @@ class Methods(
|
||||
Auth,
|
||||
EPay,
|
||||
Users,
|
||||
WebVPN,
|
||||
XG,
|
||||
):
|
||||
pass
|
||||
|
@ -10,10 +10,12 @@ class LoginWithPassword:
|
||||
self: "cqwu.Client",
|
||||
captcha_code: str = None,
|
||||
show_qrcode: bool = True,
|
||||
auth_host: str = None,
|
||||
):
|
||||
"""
|
||||
使用学号加密码登录
|
||||
"""
|
||||
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',
|
||||
@ -22,7 +24,7 @@ class LoginWithPassword:
|
||||
'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"{self.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)
|
||||
pwd_default_encrypt_salt = tree.xpath('//*[@id="pwdDefaultEncryptSalt"]/@value')[0]
|
||||
@ -46,18 +48,20 @@ class LoginWithPassword:
|
||||
'Accept-Language': 'zh-CN,zh;q=0.9',
|
||||
'Cache-Control': 'max-age=0',
|
||||
'Connection': 'keep-alive',
|
||||
'Origin': self.auth_host,
|
||||
'Referer': f'{self.auth_host}/authserver/login',
|
||||
'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"{self.auth_host}/authserver/login",
|
||||
f"{auth_host}/authserver/login",
|
||||
headers=headers,
|
||||
data=form_data,
|
||||
follow_redirects=False,
|
||||
)
|
||||
if auth_host == self.auth_host:
|
||||
if 'CASTGC' not in html.cookies.keys():
|
||||
raise UsernameOrPasswordError
|
||||
self.cookies.update(html.cookies)
|
||||
self._use_password_login = True # noqa
|
||||
self.me = await self.get_me() # noqa
|
||||
|
22
cqwu/methods/webvpn/__init__.py
Normal file
22
cqwu/methods/webvpn/__init__.py
Normal file
@ -0,0 +1,22 @@
|
||||
from httpx import URL
|
||||
|
||||
from .get_calendar import GetCalendar
|
||||
from .get_calendar_change import GetCalendarChange
|
||||
from .login_webvpn import LoginWebVPN
|
||||
|
||||
|
||||
class WebVPN(
|
||||
GetCalendar,
|
||||
GetCalendarChange,
|
||||
LoginWebVPN,
|
||||
):
|
||||
@staticmethod
|
||||
def get_web_vpn_host(url: URL, https: bool = False) -> str:
|
||||
return next(
|
||||
(
|
||||
f"https://clientvpn.cqwu.edu.cn/{'https' if https else 'http'}/{i}"
|
||||
for i in str(url).split("/")
|
||||
if i.startswith("webvpn")
|
||||
),
|
||||
None,
|
||||
)
|
42
cqwu/methods/webvpn/get_calendar.py
Normal file
42
cqwu/methods/webvpn/get_calendar.py
Normal file
@ -0,0 +1,42 @@
|
||||
import base64
|
||||
import cqwu
|
||||
from cqwu.errors import CookieError
|
||||
|
||||
|
||||
class GetCalendar:
|
||||
async def get_calendar(
|
||||
self: "cqwu.Client",
|
||||
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.request.get(
|
||||
f"{self.web_ehall_path}/appShow?appId=5299144291521305", follow_redirects=True
|
||||
)
|
||||
if "教学管理服务平台" not in jw_html.text:
|
||||
raise CookieError
|
||||
jw_host = self.get_web_vpn_host(jw_html.url)
|
||||
jw_url = f"{jw_host}/cqwljw/student/wsxk.xskcb10319.jsp"
|
||||
params = {
|
||||
"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"',
|
||||
}
|
||||
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 jw_html.replace("<title></title>", '<meta charset="UTF-8">')
|
73
cqwu/methods/webvpn/get_calendar_change.py
Normal file
73
cqwu/methods/webvpn/get_calendar_change.py
Normal file
@ -0,0 +1,73 @@
|
||||
import cqwu
|
||||
from cqwu.errors import CookieError
|
||||
|
||||
|
||||
def get_in_middle(text: str, start: str, end: str) -> str:
|
||||
return text.split(start, 1)[1].split(end, 1)[0]
|
||||
|
||||
|
||||
class GetCalendarChange:
|
||||
async def get_calendar_change(
|
||||
self: "cqwu.Client",
|
||||
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.request.get(
|
||||
f"{self.web_ehall_path}/appShow?appId=5299144291521305", follow_redirects=True
|
||||
)
|
||||
if "教学管理服务平台" not in jw_html.text:
|
||||
raise CookieError
|
||||
jw_host = self.get_web_vpn_host(jw_html.url, https=True)
|
||||
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"',
|
||||
}
|
||||
params = {
|
||||
"classPath": "C73E288D0DEA8D7F772BBD7F8FDC7E66F44C9E3992261989ECBAC5A3D722B306C6354658E0F25121E24CED075326C19885F263F369E5CD668E2EEE7CFB7EB5788F202FC6FD7DB0C96FB6995C1DD96ADE84BE3E72CFFBE9EC74FA044498BD2D21EA0439F9DC625F0EF61B7159924C542D577F814848F27128"
|
||||
}
|
||||
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',
|
||||
}
|
||||
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"',
|
||||
}
|
||||
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">')
|
21
cqwu/methods/webvpn/login_webvpn.py
Normal file
21
cqwu/methods/webvpn/login_webvpn.py
Normal file
@ -0,0 +1,21 @@
|
||||
import cqwu
|
||||
|
||||
|
||||
class LoginWebVPN:
|
||||
async def login_web_vpn(
|
||||
self: "cqwu.Client",
|
||||
):
|
||||
"""
|
||||
登录 WebVPN
|
||||
"""
|
||||
if not self._use_password_login:
|
||||
return
|
||||
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("http://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
|
||||
)
|
||||
if web_auth_path := self.get_web_vpn_host(auth_html.url):
|
||||
await self.login_with_password(auth_host=web_auth_path)
|
@ -9,8 +9,8 @@ from cqwu.errors.auth import CookieError
|
||||
class GetScore:
|
||||
async def get_score(
|
||||
self: "cqwu.Client",
|
||||
year: int = 2022,
|
||||
semester: int = 1,
|
||||
year: int = None,
|
||||
semester: int = None,
|
||||
) -> List["types.Score"]:
|
||||
"""
|
||||
获取期末成绩
|
||||
@ -18,6 +18,8 @@ class GetScore:
|
||||
Returns:
|
||||
List[types.Score]: 成绩列表
|
||||
"""
|
||||
year = year or self.xue_nian
|
||||
semester = semester or self.xue_qi
|
||||
url = "http://xg.cqwu.edu.cn/xsfw/sys/zhcptybbapp/*default/index.do#/cjcx"
|
||||
html = await self.oauth(url)
|
||||
if not html:
|
||||
|
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.3", # 包版本号,便于维护版本
|
||||
version="0.0.4", # 包版本号,便于维护版本
|
||||
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.6', # 对python的最低版本要求
|
||||
python_requires='>=3.8', # 对python的最低版本要求
|
||||
install_requires=[
|
||||
"httpx",
|
||||
"lxml",
|
||||
|
Loading…
Reference in New Issue
Block a user