python第一记,长江雨课堂抓包刷课实战

前言

    发现大学群里好多代刷网课的,确实觉得好多大学网课好费时间,而且没啥用,刚好用来实战
    一下学的Python,就当练手了。省下来的时间不是又能多敲几行代码😃​

一边省时间,还能学技能,这还不学起来
请添加图片描述

一、长江雨课堂

1.分析视频请求

F12抓包
抓包

播放过程中只有hearbest一个请求,可以确定这个应该就是我们要找的

请求是POST格式,data数据是一个json,通过多个heatbest可以看出是多个观看记录

截取一个分析如下:

c: 1561016
cards_id: 2027472
cc: ""
classroomid: 9763037
cp:424.6
d: 485.4
et: "playing"
fp: 304.5
i: 5
lob: "ykt"
n:"ali-cdn.xuetangx.com"
p:"web"
pg:"2027472_16s0j"
skuid: ""
slide: 44
sp:2
sq: 54
t:"ykt_cards"
tp: 304.5
ts: "1667910647346"
u: 35359786
uip: ""
v: 2027472
v_url: "rain://xtvideo/id/1901324024"

没发现什么加密的字段,​那就一个一个处理
复制第一个1561016,在请求里搜索

在这里插入图片描述
也只有一个请求里搜索到扫一眼可以知道这是课程的列表数据
地址
https://changjiang.yuketang.cn/v2/api/web/courses/list?identity=2
请求里也莫有加密,后面有用到的我们提取保存一下
c的意思应该是class(班级)

get_classroom_id = "https://changjiang.yuketang.cn/v2/api/web/courses/list?identity=2"
classroom_id_response = requests.get(url=get_classroom_id, headers=headers)
	for ins in json.loads(classroom_id_response.text)["data"]["list"]:
	     your_courses.append({
	         "course_name": ins["course"]["name"],
	         "classroom_id": ins["classroom_id"],
	         "course_sign": ins["university_course_series_id"],
	         "course_id": ins["course"]["id"]
	     })

card_id同上搜索也只有一个请求
地址: https://changjiang.yuketang.cn/v2/api/web/logs/learn/9763037?actype=-1&page=0&offset=20&sort=-1
9763037搜索就可以发现是classroom_id,已经保存过了
在这里插入图片描述
在这里插入图片描述

就是一个课程列表数据
和上面一样有用的数据保存一下

def get_videos_ids(course_name,classroom_id,course_sign):
    get_homework_ids = "https://changjiang.yuketang.cn/v2/api/web/logs/learn/"+str(classroom_id)+"?actype=-1&page=0&offset=20&sort=-1"
    homework_ids_response = requests.get(url=get_homework_ids, headers=headers)
    homework_json = json.loads(homework_ids_response.text)
    homework_dic = {}
    try:
        for i in homework_json["data"]["activities"]:
            if i['type'] == 14:
                # 课堂
                pass
            elif i['type'] == 9:
                # 公告
                pass
            elif i['type'] == 2:
                # 课件
                homework_dic[i['title']] = {'courseware_id' : i['courseware_id'],
                                            'id' : i['id']
                                            }
        print(course_name+"共有"+str(len(homework_dic))+"个作业喔!")
        return homework_dic
KEYValue说明
cp424.6观看时长(破解点)
d:485.4视频长度
et“playing”操作
fp304.5常量
i5常量
lob“ykt”常量
n“ali-cdn.xuetangx.com”常量
p“web”(观看方式)常量
pg“2027472_16s0j”算个小加密可能
skuid“”常量
slide44视频所在ppt页数
sp2常量
sq54常量
t“ykt_cards”常量
tp304.5常量
ts“1667910647346”13位时间戳
u35359786user_id
uip“”常量
v2027472cards_id
v_url“rain://xtvideo/id/1901324024”地址

差不多都是请求里搜索然后找位置保存,没有什么变化,只有pg后面的一小串要在js里面找,但是是个随机产生的数,可以写死。
可以下一个xhr断点
在这里插入图片描述
段下来之后一个一个看调用堆栈
到resetTimer函数的时候,可以看到参数的构建位置
也可以在这里下断点看一下都是怎么构建的
因为我要找pg, 看到

pg: e.options.id + "_" + u

所以就向上找u
在这里插入图片描述
15760行有定义

var t, i, r, o, n, d, u = Math.floor(1048576 * (1 + Math.random())).toString(36);

2.代码实现

ok所用参数都找到获取方式了接下来就是写代码的时间

# -*- coding: utf-8 -*-
# version 4
# developed by zk chen
import time
import requests
import re
import json
import execjs

class jsFun:
    def __init__(self):
        pass
    def math(self):
        fun = '''
        function a(){
            let u = Math.floor(1048576 * (1 + Math.random())).toString(36);
            return u;};
        '''
        ctx = execjs.compile(fun)
        return ctx.call("a")
# 以下的cookie复制下面图片中的内容!!!!而且脚本需在登录雨课堂状态下使用
Cookie = "这里复制粘贴Cookie"
# 以下字段不用改,下面的代码也不用改动
user_id = ""
f = jsFun()
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36 Edg/106.0.1370.42',
    'Content-Type': 'application/json',
    'Cookie': Cookie
    'authority':'changjiang.yuketang.cn',
    'method':'GET',
    'path':'/v2/api/web/courses/list?identity=2',
    'referer':'https://changjiang.yuketang.cn/v2/web/personal/info',
    'sec-fetch-dest':'empty',
    'sec-fetch-mode':'cors',
    'sec-fetch-site':'same-origin',
    # 'university-id':'2727',
    'x-csrftoken':'LE6xYWZ4rWN3UFHHDFkiykMBvffI4sCf',
    'dnt' : '1'
}

leaf_type = {
    "video": 0,
    "homework": 6,
    "exam": 5,
    "recommend": 3,
    "discussion": 4
}

def get_video_id_list(cards_id,classroomid):
    url = f'https://changjiang.yuketang.cn/v2/api/web/cards/detlist/{cards_id}?classroom_id={classroomid}'
    js = json.loads(requests.get(url=url, headers=headers).text)
    List = []
    num =1
    for ins in js['data']['Slides']:
        for i in ins['Shapes']:
            if 'playurl' in i:
                if i['file_type'] == 1:
                    List.append((i['URL'],str(num)))
        num += 1
    return List , num

def one_video_watcher(video_name,cid,user_id,classroomid,cards_id):
    classroomid = str(classroomid)
    id_list,num = get_video_id_list(cards_id,classroomid)
    for url_id,n in id_list:
        url = "https://changjiang.yuketang.cn/video-log/heartbeat/"
        get_url = f"https://changjiang.yuketang.cn/video-log/get_video_watch_progress/?user_id={user_id}&cid={cid}&video_type=ykt_cards&classroom_id={classroomid}&cards_id={cards_id}&v_url={url_id}&slide={n}"
        headers['xtbz'] = 'ykt'
        progress = requests.get(url=get_url, headers=headers)
        if_completed = '0'
        # while 1:
        try:
            js = json.loads(progress.text)[str(n) + ":"+re.search(r'[0-9]+',url_id).group()]
            videolength = js['video_length']
        except:
            print("视频" + str(n) + " " + video_name + "学习失败!")
            continue

                # time.sleep(10)
                # continue
        try:
            if_completed = re.search(r'"completed":(.+?),', progress.text).group(1)
        except:
            pass
        if if_completed == '1':
            print(video_name+"已经学习完毕,跳过")
            continue
        else:
            print(video_name+",尚未学习,现在开始自动学习")
        video_frame = 0
        val = 0
        learning_rate = 20
        t = time.time()
        timestap = int(round(t * 1000))
        while val != "1.0" and val != '1':
            heart_data = []
            for i in range(50):
                heart_data.append(
                    {
                        "i": 5,
                        "et": "loadeddata",
                        "p": "web",
                        "n": "ali-cdn.xuetangx.com",
                        "lob": "ykt",
                        "cp": video_frame,
                        "fp": 0,
                        "tp": 0,
                        "sp": 1,
                        "ts": str(timestap),
                        "u": int(user_id),
                        "uip": "",
                        "c": cid,
                        "v": cards_id,
                        "skuid": '',
                        "classroomid": classroomid,
                        "cc": '',
                        "d": videolength,
                        "pg": f"{cards_id}_"+f.math(),
                        "sq": 2,
                        "t": "ykt_cards",
                        "cards_id": cards_id,
                        "slide": n,
                        "v_url": url_id
                    }
                )
                video_frame += learning_rate
                max_time = int((time.time() + 3600) * 1000)
                timestap = min(max_time, timestap+1000*15)
            data = {"heart_data": heart_data}
            r = requests.post(url=url,headers=headers,json=data)
            try:
                error_msg = json.loads(r.text)["message"]
                if max_time< timestap+1000*15:
                    video_frame = 0
            except:
                pass
            try:

                delay_time = re.search(r'Expected available in(.+?)second.', r.text).group(1).strip()
                print("由于网络阻塞,万恶的雨课堂,要阻塞" + str(delay_time) + "秒")
                time.sleep(float(delay_time) + 0.5)
                video_frame = 0
                print("恢复工作啦~~")
                r = requests.post(url=submit_url, headers=headers, data=data)
            except:
                pass
            progress = requests.get(url=get_url,headers=headers)
            tmp_rate = re.search(r'"rate":(.+?)[,}]',progress.text)
            if tmp_rate is None:
                return 0
            val = tmp_rate.group(1)
            print("学习进度为:" + str(float(val)*100) + "%/100%" + " last_point: " + str(video_frame))
            time.sleep(0.7)
        print("视频"+str(n)+" "+video_name+"学习完成!")
    return 1

def get_videos_ids(course_name,classroom_id,course_sign):
    get_homework_ids = "https://changjiang.yuketang.cn/v2/api/web/logs/learn/"+str(classroom_id)+"?actype=-1&page=0&offset=20&sort=-1"
    homework_ids_response = requests.get(url=get_homework_ids, headers=headers)
    homework_json = json.loads(homework_ids_response.text)
    homework_dic = {}
    try:
        for i in homework_json["data"]["activities"]:
            if i['type'] == 14:
                # 课堂
                pass
            elif i['type'] == 9:
                # 公告
                pass
            elif i['type'] == 2:
                # 课件
                homework_dic[i['title']] = {'courseware_id' : i['courseware_id'],
                                            'id' : i['id']
                                            }
        print(course_name+"共有"+str(len(homework_dic))+"个作业喔!")
        return homework_dic
    except:
        print("fail while getting homework_ids!!! please re-run this program!")
        raise Exception("fail while getting homework_ids!!! please re-run this program!")

if __name__ == "__main__":
    your_courses = []

    # 首先要获取用户的个人ID,即user_id,该值在查询用户的视频进度时需要使用
    user_id_url = "https://changjiang.yuketang.cn/v/course_meta/user_info"

    id_response = requests.get(url=user_id_url, headers=headers)
    id_response.encoding="utf-8"
    try:
        user_id = re.search(r'"user_id": ([0-9]+),', id_response.text).group(1)
    except:
        print("也许是网路问题,获取不了user_id,请试着重新运行")
        raise Exception("也许是网路问题,获取不了user_id,请试着重新运行!!! please re-run this program!")

    # 然后要获取教室id
    get_classroom_id = "https://changjiang.yuketang.cn/v2/api/web/courses/list?identity=2"
    submit_url = "https://gruestc.yuketang.cn/mooc-api/v1/lms/exercise/problem_apply/?term=latest&uv_id=3194"
    headers["referer"] = 'https://changjiang.yuketang.cn/v2/web/index?date=1666686775760&newWeb=1'
    classroom_id_response = requests.get(url=get_classroom_id, headers=headers)
    try:
        for ins in json.loads(classroom_id_response.text)["data"]["list"]:
            your_courses.append({
                "course_name": ins["course"]["name"],
                "classroom_id": ins["classroom_id"],
                "course_sign": ins["university_course_series_id"],
                "course_id": ins["course"]["id"]
            })
    except Exception as e:
        print("fail while getting classroom_id!!! please re-run this program!")
        raise Exception("fail while getting classroom_id!!! please re-run this program!")

    # 显示用户提示
    for index, value in enumerate(your_courses):
        print("编号:"+str(index+1)+" 课名:"+str(value["course_name"]))
    number = input("你想刷哪门课呢?请输入编号。输入0表示全部课程都刷一遍\n")
    if int(number)==0:
        #0 表示全部刷一遍
        for ins in your_courses:
            homework_dic = get_videos_ids(ins["course_name"],ins["classroom_id"], ins["course_sign"])
            for one_video in homework_dic.items():
                one_video_watcher(one_video[0],ins["course_id"],user_id,ins["classroom_id"],cards_id=homework_dic[one_video])
    else:
        #指定序号的课程刷一遍
        number = int(number)-1
        homework_dic = get_videos_ids(your_courses[number]["course_name"],your_courses[number]["classroom_id"],your_courses[number]["course_sign"])
        for one_video in homework_dic.items():
            one_video_watcher(one_video[0], your_courses[number]["course_id"], user_id, your_courses[number]["classroom_id"],cards_id = one_video[1]['courseware_id'])

cookie替换一下
请添加图片描述

总结

大体就是播放视频,抓包,找参数,在请求里搜素,加密了就下断点看实现。
!!!主要是思路,还有一些雨课堂,学习通,mooc,什么的都差不多的。
  • 13
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值