欢迎光临
我们一直在努力

强智教务查成绩脚本

安装依赖

requirements.txt

requests>=2.28.0
beautifulsoup4>=4.12.0
pycryptodome>=3.18.0
urllib3>=2.0.0
selenium>=4.15.0

命令行执行

pip install -r requirements.txt

jsxsd.py

import requests
import time
import random
import base64
import csv
from bs4 import BeautifulSoup
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

CHARS = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678"
LOGIN_URL = "https://authserver.xxxxxx.edu.cn/authserver/login?service=http://192.168.254.188/jsxsd/"
SCORE_URL = "http://192.168.254.188/jsxsd/kscj/cjcx_list" # 成绩查询接口

def random_string(length):
return ''.join(random.choice(CHARS) for _ in range(length))

def encrypt_password(password, salt):
prefix = random_string(64)
data = prefix + password
iv = random_string(16)
key = salt.encode('utf-8')
cipher = AES.new(key, AES.MODE_CBC, iv=iv.encode('utf-8'))
ct_bytes = cipher.encrypt(pad(data.encode('utf-8'), AES.block_size))
return base64.b64encode(ct_bytes).decode('utf-8')

def check_need_captcha(session, username):
url = "https://authserver.xxxxxx.edu.cn/authserver/checkNeedCaptcha.htl"
params = {"username": username, "_": int(time.time() * 1000)}
headers = {
"X-Requested-With": "XMLHttpRequest",
"Accept": "application/json, text/javascript, */*; q=0.01",
"Referer": LOGIN_URL,
}
resp = session.get(url, params=params, headers=headers, verify=False, timeout=10)
try:
data = resp.json()
return data.get("isNeed", False)
except:
return False

def login(username, password):
session = requests.Session()
session.headers.update({
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-TW;q=0.6",
"Cache-Control": "no-cache",
"Pragma": "no-cache",
})
session.trust_env = False
session.proxies = {"http": None, "https": None}

# 1. 获取登录页,提取必要字段
resp = session.get(LOGIN_URL, verify=False, timeout=10)
soup = BeautifulSoup(resp.text, 'html.parser')
salt_input = soup.find("input", {"id": "pwdEncryptSalt"})
if not salt_input:
raise Exception("未找到 pwdEncryptSalt")
salt = salt_input["value"]
execution_input = soup.find("input", {"name": "execution"})
execution = execution_input["value"] if execution_input else ""
print(f"[+] salt: {salt}")
print(f"[+] execution: {execution}")

# 2. 检查是否需要验证码
need_captcha = check_need_captcha(session, username)
print(f"[+] 是否需要验证码: {need_captcha}")
if need_captcha:
print("[!] 系统要求验证码(当前配置为滑块验证),requests 无法自动完成。")
print(" 请改用 Selenium 方案,或手动完成滑块后获取 Cookie。")
return None

# 3. 加密密码并提交登录
encrypted_pwd = encrypt_password(password, salt)
print(f"[+] 加密密码: {encrypted_pwd[:30]}…")

payload = {
"username": username,
"password": encrypted_pwd,
"captcha": "",
"_eventId": "submit",
"cllt": "userNameLogin",
"dllt": "generalLogin",
"lt": "",
"execution": execution
}

resp = session.post(LOGIN_URL, data=payload, allow_redirects=False, verify=False, timeout=10)
print(f"[*] POST 状态码: {resp.status_code}")

if resp.status_code == 200 and "login" in resp.url:
with open("login_fail.html", "w", encoding="utf-8") as f:
f.write(resp.text)
print("[!] 登录失败,详细页面保存至 login_fail.html")
return None

# 4. 跟随重定向直到进入教务系统
max_redirects = 10
while resp.status_code in (301, 302, 303, 307, 308):
location = resp.headers.get("Location")
if not location:
break
if location.startswith("/"):
location = "https://authserver.xxxxxx.edu.cn" + location
print(f"[→] 重定向: {location}")
resp = session.get(location, allow_redirects=False, verify=False, timeout=10)
max_redirects -= 1
if max_redirects <= 0:
raise Exception("重定向次数过多")

print(f"[+] 登录成功,最终 URL: {resp.url}")
return session

def fetch_scores(session):
"""请求成绩页面并解析表格,返回成绩列表(字典格式)"""
resp = session.post(SCORE_URL, timeout=10)
resp.encoding = 'utf-8'
if resp.status_code != 200:
print(f"[!] 成绩页面请求失败,状态码 {resp.status_code}")
return None

soup = BeautifulSoup(resp.text, 'html.parser')
table = soup.find('table', id='dataList')
if not table:
print("[!] 未找到成绩表格,可能未登录或页面结构变化")
return None

rows = table.find_all('tr')[1:] # 跳过表头
if not rows:
print("[!] 表格无数据,可能暂无成绩")
return []

# 定义字段(与页面表头对应)
columns = [
'序号', '开课学期', '课程编号', '课程名称',
'成绩', '成绩标识', '学分', '总学时', '绩点',
'补重学期', '考核方式', '考试性质', '课程属性', '课程性质', '通选课类别'
]
data = []
for row in rows:
cells = row.find_all('td')
values = [cell.get_text(strip=True) for cell in cells]
# 补齐可能缺少的列
while len(values) < len(columns):
values.append('')
row_dict = dict(zip(columns, values[:len(columns)]))
data.append(row_dict)
return data

def print_and_save(data, filename='scores.csv'):
"""打印成绩并保存为 CSV 文件"""
if not data:
print("[!] 无成绩数据")
return

print("\\n" + "="*60)
print("成绩查询结果:")
for row in data:
print(f"{row['序号']}. {row['课程名称']} | 成绩:{row['成绩']} | 学分:{row['学分']} | 绩点:{row['绩点']}")

with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.DictWriter(f, fieldnames=data[0].keys())
writer.writeheader()
writer.writerows(data)
print(f"\\n[+] 成绩已保存到 {filename}")

if __name__ == "__main__":
# 配置用户名和密码
USERNAME = ""
PASSWORD = ""

sess = login(USERNAME, PASSWORD)
if sess:
scores = fetch_scores(sess)
if scores is not None:
print_and_save(scores)
else:
print("[!] 登录失败,无法获取成绩")

image-20260616215008185

赞(0)
未经允许不得转载:171主机测评 » 强智教务查成绩脚本
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址