自从二月份开始,由于疫情爆发,只好在家上网课,每天上今日校园填写相同问题的每日一报,就开始想,我每天都宅在家里面,能有什么问题,不如利用一点爬虫的知识做一个自动填写的脚本,可是遇到很多障碍,例如,手机app弄代理,抓包不到,因为今日校园用了ssl的加密传输方式,难以抓包分析,这也让我的兴趣沉下去了。
直到开学返校后,原本的每日一报变成了每日三签了,嫌麻烦的我又来了兴趣,后来让我在b站看到子墨的自动签到项目。
我的个人博客 链接
子墨的博客 链接
子墨的github 链接
因为子墨的自动签到项目依赖于他的服务器api,最近使用的人多了起来,就频繁出现api接口失效的情况,自己又不想买服务器搭建,所以就自己动手,用纯python代码获取登陆后的cookies,替换原来使用的api接口。
首先打开 https://www.cpdaily.com/v6/config/guest/tenant/list
在这个页面里CRTL - F 搜索学校名字,找到后面这些字段
我的学校joinType为NOTCLOUD,没研究过其他学校的,所以自行比较吧
打开idsUrl的链接,那就是学校的云端登录页面
随便填个账号登录,抓取登录所提交的数据包看看提交了什么数据
密码是加密后的108位密文
It,dllt,execution,rmShown是是藏在登录页面的信息,每次刷新登录页面,lt,execution的值都会改变
清空本地cookie,重新刷新页面
刷新页面后,查看第一个数据包的响应头有set-cookie字段,route、JSESSIONID是我们所需要的
##url、headers、data自行获取
##获取 route、JSESSIONID
response = requests.get(url, headers=headers, data = payload)
if response.status_code == 200:
##response.cookies是CookieJar类型,requests.utils.dict_from_cookiejar可以把cookiejar类型转换成dict类型
cookie = requests.utils.dict_from_cookiejar(response.cookies)
JSESSIONID = cookie["JSESSIONID"]
route = cookie["route"]
尝试正确账号密码登录,查看登录的第一个数据包,表单数据中提交username,加密后的password,It,dllt,execution
请求表头包含前面获取到的route,JSESSIONID
响应表头中的set-cookie包含我们需要的CASTGC,CASPRIVACY,iPlanetDirectory字段
登录后,页面会跳转,而响应表头中的Location就是跳转用的
##获取CASTGC、CASPRIVACY、iPlanetDirectoryPro
form = [
"username":xxxx,
"password":xxx,
"lt":xxx,
"dllt":xxx,
"execution":xxx,
"_eventld":xxx,
"rmShown":xxx,
]
res = requests.post(url,headers=headers2,data=form)
response_headers = res.history[0].headers##因为页面重定向,所以需要获取响应历史的表头
set_cookie = response_headers["SET-COOKIE"]
CASTGC = re.findall("CASTGC=(.*?);",set_cookie)[0]
CASPRIVACY = re.findall("CASPRIVACY=(.*?);",set_cookie)[0]
iPlanetDirectoryPro = re.findall("iPlanetDirectoryPro=(.*?);",set_cookie)[0]
Location = response_headers["Location"]
请求Location的链接后就能获取最重要的acw_tc、MOD_AUTH_CAS字段了
#获取acw_tc、MOD_AUTH_CAS
res2 = requests.get(url=Location,headers=headers3)
response_headers = res2.history[0].headers##因为页面重定向,所以需要获取响应历史的表头
set_cookie2 = response_headers["SET-COOKIE"]
acw_tc = re.findall("acw_tc=(.*?);",set_cookie2)[0]
MOD_AUTH_CAS = re.findall("MOD_AUTH_CAS=(.*?);",set_cookie2)[0]
Location = response_headers["Location"]
以上就是获取route等字段的思路和方法,问题来了,最开始登录所需要的密码如何加密,lt等字段如何获取呢
CTRL-F搜索LT-,可以查看隐藏在登录页面html的字段
##xpath方法
LT = html.xpath('//*[@id="casLoginForm"]/input[1]/@value')[0]
##key是隐藏在登录界面的加密钥匙,用来加密成108位密码
key = html.xpath('//*[@id="pwdDefaultEncryptSalt"]/@value')[0]
dllt = html.xpath('//*[@id="casLoginForm"]/input[2]/@value')[0]
execution = html.xpath('//*[@id="casLoginForm"]/input[3]/@value')[0]
rmShown = html.xpath('//*[@id="casLoginForm"]/input[5]/@value')[0]
##lxml不知道如何上传到云函数,所以还是用正则吧
LT = re.findall('name="lt" value="(.*)"', html)[0]
key = re.findall('id="pwdDefaultEncryptSalt" value="(.*?)"',html)[0]
dllt = re.findall('name="dllt" value="(.*)"',html)[0]
execution = re.findall('name="execution" value="(.*?)"',html)[0]
rmShown = re.findall('name="rmShown" value="(.*?)"',html)[0]
其中id为pwddefaultEncryptSalt的value值是密码加密的key,用来加密成108位密码的,用到的方法是AES加密
import math
import random
import base64
from Crypto.Cipher import AES
# 获取随机字符串
def getRandomString(length):
chs = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
result = ''
for i in range(0, length):
result += chs[(math.floor(random.random() * len(chs)))]
return result
# AES加密
def EncryptAES(s, key, iv='1' * 16, charset='utf-8'):
key = key.encode(charset)
iv = iv.encode(charset)
BLOCK_SIZE = 16
pad = lambda s: (s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * chr(BLOCK_SIZE - len(s) % BLOCK_SIZE))
raw = pad(s)
cipher = AES.new(key, AES.MODE_CBC, iv)
encrypted = cipher.encrypt(bytes(raw, encoding=charset))
return str(base64.b64encode(encrypted), charset)
# 金智的AES加密过程
def AESEncrypt(data, key):
return EncryptAES(getRandomString(64) + data, key, key)
pwd = AESEncrypt("密码",key)
有了加密后的pwd,It等字段就可以实现模拟登录了,就可以获取到acw_tc、MOD_AUTH_CAS等字段了,有了这些认证身份的东西,后面搞自动签到就变得简单了,通过手机端抓包获取,分析就可以实现多种功能了。