近期经常需要写一些和华师大数据库交互的小工具,比如导出课程表,获取绩点等。这里提供使用 Python 登录数据库的方法,将登录信息使用 request
包记录在一个 request.session
中。
这里涉及到四个函数。
main()
:一个示例的交互逻辑ECNULogin()
主要的登录函数GetCode()
用于获取验证码。这里把手动输入的两行注释掉了,如果不想安装tenserflow
,则可以注释掉下面的识别部分,手动输入验证码。不过华师大的验证码很好识别。目前我还没有遇到pytesseract
识别失败的情况。GetRSA()
RSA 加密登录信息。这里调用的是华师大数据库中的 js 文件,并使用execjs
来调用内部的 strEnc 函数。
from PIL import Image # 手动输入验证码
import pytesseract # 自动识别验证码
from lxml import etree
import sys
import requests
import getpass
import execjs # 用于加密
# 记录登录信息的 session
s = requests.session()
mainurl = 'https://portal1.ecnu.edu.cn/cas/login?service=http%3A%2F%2Fapplicationnewjw.ecnu.edu.cn%2Feams%2Fhome.action'
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'Refer': 'https://portal1.ecnu.edu.cn/cas/login?service=http%3A%2F%2Fapplicationnewjw.ecnu.edu.cn%2Feams%2Fhome.action%3Bjs'}
def GetRSA(username, password):
# 获取 des.js 里的内容
jsstr = requests.get('https://portal1.ecnu.edu.cn/cas/comm/js/des.js').text
desJS = execjs.compile(jsstr)
# 调用 strEnc 函数实现 rsa 加密
try:
rsa = desJS.call('strEnc', username + password, '1', '2', '3')
except:
print('加密错误。')
return rsa
def GetCode():
"发送一次新的 get 请求并获取验证码,让用户填写。"
print('正在获取验证码...')
r = s.get(mainurl, headers=headers)
imgraw = s.get('https://portal1.ecnu.edu.cn/cas/code')
with open(sys.path[0] + '/temp.jpg', 'wb+') as f:
f.write(imgraw.content)
# OpenFile(sys.path[0] + '/data/temp.jpg')
# captacha = input('请输入验证码:')
print('正在识别验证码...')
img = Image.open(sys.path[0] + '/temp.jpg')
captacha = pytesseract.image_to_string(img)
print('识别结果: {}'.format(captacha))
return captacha
def ECNULogin(username='', password='', ifEnterPassword=False):
"""
返回值:
0 - 成功登陆
1 - 验证码错误
2 - 密码错误
3 - 未知错误
"""
if (ifEnterPassword == True):
username = input('请输入你的公共数据用户名(学号):')
password = getpass.getpass('请输入你的公共数据库密码(直接输入即可,已关闭输入回显):')
code = GetCode()
# 用户名和密码经过了 RSA 加密。
postData = {
'code': code,
'rsa': GetRSA(username, password),
'ul': len(username),
'pl': len(password),
'lt': 'LT-211100-OG7kcGcBAxSpyGub3FC9LU6BtINhGg-cas',
'execution': 'e1s1',
'_eventId': 'submit'
}
print('正在尝试登录...')
r = s.post(mainurl, data=postData)
elements = etree.HTML(r.content)
errors = elements.xpath('//*[@id="errormsg"]')
if len(errors) == 0:
realName = elements.xpath('//a[contains(@title, "查看登录记录")]/font/text()')[0]
print('登录成功:', realName)
return 0
elif elements.xpath('//*[@id="errormsg"]/text()')[0] == "验证码有误":
return 1
elif elements.xpath('//*[@id="errormsg"]/text()')[0] == "用户名密码错误":
return 2
else:
error_text = elements.xpath('//*[@id="errormsg"]/text()')[0]
print(error_text)
return 3
def main():
username = input('请输入你的公共数据用户名(学号):')
password = getpass.getpass('请输入你的公共数据库密码(直接输入即可,已关闭输入显示):')
feedback = ECNULogin(username, password, ifEnterPassword=False)
while feedback != 0:
if feedback == 1:
print('验证码识别错误,请重试。')
feedback = ECNULogin(username, password, ifEnterPassword=False)
elif feedback == 2:
print('用户名或密码错误,请重试。')
feedback = ECNULogin(ifEnterPassword=True)
else:
print('未知错误,输入 0 以重试,输入其他任何内容退出。')
c = input()
if (c == '0'):
feedback = ECNULogin(ifEnterPassword=True)
else:
print('无法连接。')
main()
登录成功后,信息就会被记录在 s
中,之后使用该 session
跳转所有校内网站都可以直接登录。
至于可以用来干什么……。
恩。理论上是可以用来抢课的。