全新正方系统爬虫抢课,成绩获取(凯里学院)

本文详细介绍了如何编写一个针对凯里学院官网的爬虫,包括使用第三方库处理加密、获取验证码、模拟登录过程,以实现自动抢课和数据抓取。
摘要由CSDN通过智能技术生成

免责声明:本文章涉及到的应用仅供学习交流使用,不得用于任何商业用途,数据来源于互联网公开内容,没有获取任何私有和有权限的信息(个人信息等)。由此引发的任何法律纠纷与本人无关!禁止将本文技术或者本文所关联的Github项目源码用于任何目的。


 

1. 爬虫内容简介 

        全网没几个完整的正方抢课,我自己写了个供大家参考,关于正方系统的学校官网爬虫的学习,以凯里学院为例子分析网站的结构,完成抢课,提取学习成绩等操作。

7bdffb8e98b84fc5b6f81b3d21517f33.png

 

2. 使用的第三方库

import execjs                    # 用来执行js脚本
import requests                  # 用来请求网页,获取网页内容
from bs4 import BeautifulSoup    # 用来解析网页内容
import csv                       # 用来写入csv文件
import re                        # 用来匹配内容
import time                      # 用来延时
import ddddocr                   # 用来识别验证码
import os                        # 用来文件操作

 

3. 主页请求内容分析结果(我这个带了加密,看自己学校的带不带)

    1. 随便输入几个请求看看提交数据

                a29bc72fea10406680c741c864aef8b6.png

                e53f41bb394a47148f1f8001f9af70af.png

 

# 第一次请求

__LASTFOCUS: 
__VIEWSTATE: qwUndoHlDMDrfSoLU73kgkw2EMjeMswhpCyOkTB5qTgNoqx8q2eEPy+e9Tv2UuRPolkwrg==
__VIEWSTATEGENERATOR: 9BD98A7D
__EVENTTARGET: 
__EVENTARGUMENT: 
txtUserName: 456
TextBox2: 8d0237f0bba6d2cc2fa6aaeb41ffa33fbb907263ee4590b0df54a52e2b0d09a8812bf0e0ce489522ae9baff88b45273509d90fcac519d328022921d680ee8edc947af6398d55c3fbf64078b1fd3cc98f46e2c434849902501f535504db882c8329a5d973e0e7cf9a0170c4b11b54f3f81b480c5dac1d92ce2ca85f4dc73b0116
txtSecretCode: 456
RadioButtonList1: 学生
Button1: 登录
txtKeyExponent: 010001
txtKeyModulus: 9E0B832A27697B3DD3158A3AAC3EBD609202F374AAD0BA0A7A66D02F466B4E82ABDC9235DFFE6F10645DB3D35DF68AE49628ABC6A7C379EC913DE3C701FC30A1CC4F39516A50F06350A5DD0D82215388DEE3758D87329EFCCF1AA1AC535B4966372CB3523536A3A742272A02805B717974A6021963635CC32AB4AE78CA498539


# 第二次请求

__LASTFOCUS: 
__VIEWSTATE: Z9Z9Kj7O2ka4zxmV93gdApgH8n3upKJBHrTGMm+dBlnQbzO6xwEAhkhFinTvgHxOLmtugw==
__VIEWSTATEGENERATOR: 9BD98A7D
__EVENTTARGET: 
__EVENTARGUMENT: 
txtUserName: 456546
TextBox2: 6fe3c039ea83b04c7d87cd2d135cf4ff568830936cb5e119eaa27432953f41e57f19243e002cb11cf78fb124c720fe7f259a5516de74c1c4ea728a60471e5a87c485c1a7a7d340dcf70f9867d143c0638fca9388958326165f9543000bec5d585ea435f24dff77c3a08bc66c76c214a7adbc921918caae223ace0926d3746c93
txtSecretCode: 456
RadioButtonList1: 学生
Button1: 登录
txtKeyExponent: 010001
txtKeyModulus: 9E0B832A27697B3DD3158A3AAC3EBD609202F374AAD0BA0A7A66D02F466B4E82ABDC9235DFFE6F10645DB3D35DF68AE49628ABC6A7C379EC913DE3C701FC30A1CC4F39516A50F06350A5DD0D82215388DEE3758D87329EFCCF1AA1AC535B4966372CB3523536A3A742272A02805B717974A6021963635CC32AB4AE78CA498539

  2. 我这直接说结果,随便请求两次看请求的值有没有变化

        一共3个变值,其他的都是固定的。

__VIEWSTATE:                         加密

txtUserName:                            用户名
TextBox2:                                  加密
txtSecretCode:                          密码
txtKeyModulus:                         固定

   3. 分析加密使用逆向,查看源代码。看到他调用的库,经典的rsa加密

1f385e6d77124f8289b21085a2b95e27.png

  • 看见他的js代码,逆向一般就是js,每个学校的不一样,一般不会很难,复制就可以。

ba2e1f8119294753bf67838a60978e93.png

  • 将他使用的加密代码和依赖的库复制到py项目文件夹中

89b8351ecd91425eabf4ea7657193a21.png

        在源代码看看变值, 最后要的TextBox2 加密内容 需要的strPublicKeyExponent 和 strPublicKeyModulus也在页面源代码

__VIEWSTATE:                         每次页面生成

txtUserName:                            用户名
TextBox2:                                  加密
txtSecretCode:                          密码
txtKeyModulus:                         固定

 

4.分析完毕,开始写代码

1. 用session.get方法获取请求,拿到页面源代码,获取所需要的__VIEWSTATE

strPublicKeyExponent

strPublicKeyModulus

index_url = "http://sys.kluniv.edu.cn:8003/"
session = requests.session()

header = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 "
                  "Safari/537.36 Edg/121.0.0.0",
    "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-Encoding": "gzip, deflate",
    "Cookie": "_gscu_670124149=805331319upx0619; _ga=GA1.1.202793893.1685956507; "
                       "_ga_QYKCGTHFGK=GS1.1.1685956507.1.1.1685956952.0.0.0; "
                       "ASP.NET_SessionId=sekouqhtdlhnftj0rzj5ezwe",
    "Host": "sys.kluniv.edu.cn:8003",
}

resp = session.get(index_url, headers=header)
print(resp.status_code)
soup = BeautifulSoup(resp.text, 'lxml')
viewState = soup.find('input', attrs={'name': '__VIEWSTATE'})['value']
public_key_exponent = soup.find('input', attrs={'name': 'txtKeyExponent'})['value']
public_key_modulus = soup.find('input', attrs={'name': 'txtKeyModulus'})['value']
yzm_url = soup.find()

2. 将复制的js代码用 execjs 库读取运行(不会的自己查)

​
with open("rea.js", "r", encoding="utf-8") as file:
    result = file.read()
    file.close()
js = execjs.compile(result)
TextBox2 = js.call("password_ase", public_key_exponent, public_key_modulus, password)

​

rea.js包括了这4个js库的所有代码,一个不少的复制到自己创建的rea.js中,加入加密方法。

加密方法  password_ase 是分析源代码来的写为下面截图。返回的就是textbox2.

faee13f0bab341329244b2be6062151a.png

82afca0433d24662aded151357cae398.png

function password_ase(strPublicKeyExponent, strPublicKeyModulus, password) {
    setMaxDigits(129);
    var key = new RSAKeyPair(strPublicKeyExponent, "", strPublicKeyModulus);
     console.log("Hello, World!");
    var pwdMD5Twice = password;
    var pwdRtn = encryptedString(key, pwdMD5Twice);
    var TextBox2 = pwdRtn;

    return TextBox2;
}

3. 加密的逆向做完了,现在就是请求登录,还需要解决验证码。

找到url,这个也在源代码中,一样获取img_url ,其中get需要带有safekey参数,在url中用split获取。

e54c92c0e66d41d59b536c2ae2c1dea9.png

c5164d617c934096ac5e788dc5905b40.png

resp = session.get(index_url, headers=header)
print(resp.status_code)
soup = BeautifulSoup(resp.text, 'lxml')
viewState = soup.find('input', attrs={'name': '__VIEWSTATE'})['value']
public_key_exponent = soup.find('input', attrs={'name': 'txtKeyExponent'})['value']
public_key_modulus = soup.find('input', attrs={'name': 'txtKeyModulus'})['value']
img_url = soup.find('img', attrs={'id': 'icode'})['src']
SafeKey = img_url.split("=")[-1]

获取验证码并保存

# 发送请求 获取图片
img_url_total = index_url + img_url
print(img_url_total)
data_img = {
    "SafeKey": SafeKey
}
resp_img = session.get(img_url_total, headers=header, stream=True, data=data_img)
print(resp_img.status_code)
with open(r'yzm.jpg', 'wb') as f:
    f.write(resp_img.content)
f.close()
获取成功后使用循环判断,图片是否保存成功,这个函数挺多余的,不要也一样。这样验证码也到手了,登录需要的数据就全部齐全了。
def one_sleep():
    time.sleep(1)

# 识别验证码 识别之前以防图片还没有下载完成 判断文件是否存在 不存在时休眠1s
while not os.path.exists("yzm.jpg"):
    one_sleep()
ocr = ddddocr.DdddOcr()
with open('yzm.jpg', 'rb') as f:
    img_bytes = f.read()
yzm = ocr.classification(img_bytes)

4. 开始登录,发送post请求,请求完成,在带着需要的参数get登陆后的页面,查看返回数据,返回成功我们就完成了登录,剩下的就是请求需要爬的页面获取数据或者请求。

data = {
  "__VIEWSTATE": viewState,
  "__VIEWSTATEGENERATOR": "9BD98A7D",
  "txtUserName": user_id,
  "TextBox2": TextBox2,
  "txtSecretCode": yzm,
  "RadioButtonList1": "学生",
  "Button1": "登录",
  "txtKeyExponent": "010001",
  "txtKeyModulus": public_key_modulus
}
# print(data)
_resp = session.post(index_url, headers=header, data=data)
login_data = {
    "xh": user_id
}
login_resp = session.get(index_url + f"/xs_main.aspx?xh={user_id}", headers=header, data=login_data)
print(login_resp.status_code)
print(login_resp.text)

5a604ec0b78a4b109b423b258a31d2bd.png

d5ec2a4f8742447dbcf2e4e30378b6d3.png

5. 这是一个非常简单的逆向爬虫,做为初学者是非常容易的,后面的爬取成绩等具体功能会慢慢完善,大部分都是倒在了登录的逆向。

 6. 完整代码

 

"""
新凯里学院官网
"""
import execjs                    # 用来执行js脚本
import requests                  # 用来请求网页,获取网页内容
from bs4 import BeautifulSoup    # 用来解析网页内容
import csv                       # 用来写入csv文件
import re                        # 用来匹配内容
import time                      # 用来延时
import ddddocr                   # 用来识别验证码
import os                        # 用来判断文件是否存在

def one_sleep():
    time.sleep(1)

index_url = "http://sys.kluniv.edu.cn:8003"
session = requests.session()

header = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 "
                  "Safari/537.36 Edg/121.0.0.0",
    "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-Encoding": "gzip, deflate",
    "Cookie": "_gscu_670124149=805331319upx0619; _ga=GA1.1.202793893.1685956507; "
                       "_ga_QYKCGTHFGK=GS1.1.1685956507.1.1.1685956952.0.0.0; "
                       "ASP.NET_SessionId=sekouqhtdlhnftj0rzj5ezwe",
    "Host": "sys.kluniv.edu.cn:8003",
}

resp = session.get(index_url, headers=header)
print(resp.status_code)
soup = BeautifulSoup(resp.text, 'lxml')
viewState = soup.find('input', attrs={'name': '__VIEWSTATE'})['value']
public_key_exponent = soup.find('input', attrs={'name': 'txtKeyExponent'})['value']
public_key_modulus = soup.find('input', attrs={'name': 'txtKeyModulus'})['value']
img_url = soup.find('img', attrs={'id': 'icode'})['src']
SafeKey = img_url.split("=")[-1]
yzm_url = soup.find()
user_id = 2021402078
password = ""

# print(img_url)

# js逆向 textbox2
with open("rea.js", "r", encoding="utf-8") as file:
    result = file.read()
    file.close()
js = execjs.compile(result)
TextBox2 = js.call("password_ase", public_key_exponent, public_key_modulus, password)


# 发送请求 获取图片
img_url_total = index_url + img_url
# print(img_url_total)
data_img = {
    "SafeKey": SafeKey
}
resp_img = session.get(img_url_total, headers=header, stream=True, data=data_img)
print(resp_img.status_code)
with open(r'yzm.jpg', 'wb') as f:
    f.write(resp_img.content)
f.close()


# 识别验证码 识别之前以防图片还没有下载完成 判断文件是否存在 不存在时休眠1s
while not os.path.exists("yzm.jpg"):
    one_sleep()
ocr = ddddocr.DdddOcr()
with open('yzm.jpg', 'rb') as f:
    img_bytes = f.read()
yzm = ocr.classification(img_bytes)




data = {
  "__VIEWSTATE": viewState,
  "__VIEWSTATEGENERATOR": "9BD98A7D",
  "txtUserName": user_id,
  "TextBox2": TextBox2,
  "txtSecretCode": yzm,
  "RadioButtonList1": "学生",
  "Button1": "登录",
  "txtKeyExponent": "010001",
  "txtKeyModulus": public_key_modulus
}
# print(data)
_resp = session.post(index_url, headers=header, data=data)
login_data = {
    "xh": user_id
}
login_resp = session.get(index_url + f"/xs_main.aspx?xh={user_id}", headers=header, data=login_data)
print(login_resp.status_code)
print(login_resp.text)


resp.close()
login_resp.close()

 

 

  • 28
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值