就在我刚刚写完旧版正方系统爬虫的时候(旧版正方系统爬虫代码)
学校就出了新版的正方教务系统
估计是装空调的钱有的多
那就开始讲解叭~
在Fiddler中出现了一条post数据
点一下WebForms看看带了什么数据进去
Body | Value |
---|---|
time | time库里的time~ |
csrftioken | 不知道什么东西 怎么没出现过 |
yhm | 用户名是明文唉 大家心知肚明就好了 |
mm | 这个就是输入的密码了 一看就经过了加密 |
什么??加密过了??那是怎么加密的呢
在主页面经过审查元素发现了js的文件
啊~在login.js里面 找到了这些代码
$.getJSON(_path+"/xtgl/login_getPublicKey.html?time="+new Date().getTime(),function(data){
modulus = data["modulus"];
exponent = data["exponent"];
});
------我是分割符------
var rsaKey = new RSAKey();
rsaKey.setPublic(b64tohex(modulus), b64tohex(exponent));
var enPassword = hex2b64(rsaKey.encrypt($("#mm").val()));
$("#mm").val(enPassword);
$("#hidMm").val(enPassword);
大概翻译一下就是
获取了publishkey之后使用publishkey对明文的密码做RSA算法加密再使用BASE64填充
升级了系统不就是不用验证码了吗 为什么做爬虫更累了呢
首先准备一个session(会话)
session = requests.Session()
time_now = int(time.time())
session.headers.update({
'Accept': 'text/html, */*; q=0.01',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0',
'X-Requested-With': 'XMLHttpRequest',
'Connection': 'keep-alive',
'Content-Length': '0',
'Content-Type': 'application/x-www-form-urlencoded',
'Host': 'qjxyjw.hznu.edu.cn',
'Referer': 'http://qjxyjw.hznu.edu.cn/jwglxt/xtgl/index_initMenu.html?jsdm=&_t=' + str(time_now),
'Upgrade-Insecure-Requests': '1'
})
至于这个头是怎么来的 详情Fiddler
# 准备publickey
url = 'http://qjxyjw.hznu.edu.cn/jwglxt/xtgl/login_getPublicKey.html?time=' + str(time_now)
r = session.get(url)
publickey = r.json()
提一下这个csrftoken 找来找去最后在访问主页面的时候找到了
# 准备csrftoken
url = 'http://qjxyjw.hznu.edu.cn/jwglxt/xtgl/login_slogin.html?language=zh_CN&_t=' + str(time_now)
r = session.get(url)
r.encoding = r.apparent_encoding
soup = BeautifulSoup(r.text, 'html.parser')
csrftoken = soup.find('input', attrs={'id': 'csrftoken'}).attrs['value']
说一下这个加密 虽然github上面有大佬从js里面移植过来的rsa算法 但是我无论如何都用不来
只好用别人的java程序 在python里面使用txt对密码传输(虽然很low但是是无奈之举了)
url = r"C:\Users\Administrator\Desktop\new_jiaowu"
f = open(url + r"\code.txt", "w")
f.write(studentid + '\n')
f.write(studentpwd + '\n')
f.write(publickey['modulus'] + '\n')
f.write(publickey['exponent'] + '\n')
f.close()
try:
subprocess.Popen('code.exe', shell=False, close_fds=True)
except:
print("启动加密程序错误")
sys.exit()
time.sleep(1)
with open(url + r"\encode.txt", 'r') as f:
list1 = f.readlines()
for i in range(0, len(list1)):
list1[i] = list1[i].rstrip('\n')
id = list1[0]
rsacode = list1[1]
f.close()
if id != studentid:
print("RSA加密错误...等待调试")
sys.exit()
对应的java代码在笔记本里 给个空位=。=
等待更新
嘿嘿嘿东西都准备好了 尝试登陆吧
try:
url = 'http://qjxyjw.hznu.edu.cn/jwglxt/xtgl/login_slogin.html'
data = {
'csrftoken': csrftoken,
'mm': rsacode,
'mm': rsacode,
'yhm': studentid
}
result = session.post(url, data=data)
return result.text
except Exception as e:
print(e)
如果密码输入错误的话会有提示框 这里使用in就可以简单的实现判断了
if '用户名或密码不正确' in result.text:
return "用户名或密码不正确"
最后 封装一下 就实现了主页面登陆的按钮啦
贴个代码
def login(studentid, studentpwd, session):
time_now = int(time.time())
# 准备publickey
url = 'http://qjxyjw.hznu.edu.cn/jwglxt/xtgl/login_getPublicKey.html?time=' + str(time_now)
r = session.get(url)
publickey = r.json()
# 准备csrftoken
url = 'http://qjxyjw.hznu.edu.cn/jwglxt/xtgl/login_slogin.html?language=zh_CN&_t=' + str(time_now)
r = session.get(url)
r.encoding = r.apparent_encoding
soup = BeautifulSoup(r.text, 'html.parser')
csrftoken = soup.find('input', attrs={'id': 'csrftoken'}).attrs['value']
# 加密密码
url = r"C:\Users\Administrator\Desktop\new_jiaowu"
f = open(url + r"\code.txt", "w")
f.write(studentid + '\n')
f.write(studentpwd + '\n')
f.write(publickey['modulus'] + '\n')
f.write(publickey['exponent'] + '\n')
f.close()
try:
subprocess.Popen('code.exe', shell=False, close_fds=True)
except:
print("启动加密程序错误")
sys.exit()
time.sleep(1)
with open(url + r"\encode.txt", 'r') as f:
list1 = f.readlines()
for i in range(0, len(list1)):
list1[i] = list1[i].rstrip('\n')
id = list1[0]
rsacode = list1[1]
f.close()
if id != studentid:
print("RSA加密错误...等待调试")
sys.exit()
# 单击登录按钮
try:
url = 'http://qjxyjw.hznu.edu.cn/jwglxt/xtgl/login_slogin.html'
data = {
'csrftoken': csrftoken,
'mm': rsacode,
'mm': rsacode,
'yhm': studentid
}
result = session.post(url, data=data)
return result.text
except Exception as e:
print(e)
老样子 我们先模拟登陆使用Fiddler看看是怎么一个过程
这里可以一次性查询所有成绩有一点点方便
铛铛 在Fiddler中发现了如下数据
Body | Value |
---|---|
xnm | 学年名 |
xqm | 学期名 |
_search | 固定false |
nd | 这个和之前的time一样的啦 都是time库里面的time函数整数化一下就好了 |
query* | 固定的 照抄照抄 |
time | 固定0(总觉得这个的存在是正方有点问题) |
还是提一下这里学期名 发现第一学期发送的是3 第二学期发送的是12
def score_page(session, year, term):
url = 'http://qjxyjw.hznu.edu.cn/jwglxt/cjcx/cjcx_cxDgXscj.html?doType=query&gnmkdm=N305005'
# 定义所有学期 3为第一学期 12为第二学期
if term == "1":
term = "3"
elif term == "2":
term = "12"
try:
data = {'_search': 'false',
'nd': int(time.time()),
'queryModel.currentPage': '1',
'queryModel.showCount': '15',
'queryModel.sortName': '',
'queryModel.sortOrder': 'asc',
'time': '0',
'xnm': year,
'xqm': term
}
result = session.post(url, data=data)
result = result.json()
return result
except:
return '[Error]获取该学期成绩失败'
既然成绩我们都获取到啦 还很方便给的是json数据 so 你懂了吗
stu_name = result['items'][0]['xm']
sch_stu = result['items'][0]['xslb']
institute = result['items'][0]['jgmc']
stu_class = result['items'][0]['bj']
print('姓名:{}\t学历:{}\t\t学院:{}\t班级:{}'.format(stu_name, sch_stu, institute, stu_class))
# dt = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
plt = '{0:{4}<15}\t{1:{4}<6}\t{2:{4}<6}\t{3:{4}<4}'
for i in result['items']:
print(plt.format(i['kcmc'], i['bfzcj'], i['jd'], i['jsxm'], chr(12288)))
# sql.insert_score(studentid, year, term, i['kcmc'], i['bfzcj'], i['jd'], i['jsxm'], dt)
因为后面我做好了和sql数据库的写入 作为演示 我都注释掉啦
嗝。。因为加密密码的环境问题 之后用笔记本再贴进来啦 给个空位=。=
(我是图片)