作为一名职业懒狗,自然不会花大量时间在选修课上。之前体验过一些刷课的脚本觉得很神奇,但是现在好像使用起来有诸多不便,近日在本站上看到两篇质量很高的帖子,分别从原理和代码上解释并实现了雨课堂刷课的操作。
于是跟进并学习了一下
干货
先把跟进的结果分享给大家:
最后的python脚本可以实现刷视频和评论的功能。因为刷图片不计分所以没写,另外刷题因为没有标答所以相应的功能也没有呈现
python脚本仅需修改5处即可实现对应功能,集成度较高,方便操作,下面是链接:
[链接]:https://pan.baidu.com/s/16cfb_qp3HnbX8s-l2nHXYw
[提取码]:cccd
操作过程:
所需修改的5处地方分别对应第4、7、8、9、10行代码,表示操作对象的编号和发包的参数
如何进行修改:
1.首先登陆长江雨课堂至如下界面
2.按F12进入开发者工具,点击弹窗右上角的 “网络”,再点击你需要刷的课程,会有如下图的显示
3.将代码第7行sku_id的值修改为上图free_sku_id的值,将代码第8行classroomid的值修改为上图id的值
4.再点击标头,向下翻至请求标头的位置,将cookie和x-csrftoken的值复制到第9行和第10行的位置上去。
5.翻到学习日志底部,点击最后一个任务,看右侧弹窗中数据包有何更新
这个1574打头的8位数是任务编号,也就是我们numlist列表里面需要保存的值,用同样的方式去看第一个任务的编号,判断编号任务的区间,用代码生成一个以第一个编号为首项,公差为1的递增序列,最后一个任务编号不要设为尾项,尽量把数据范围扩大一些,然后将生成的序列用逗号隔开保存在第四行numlist当中。
上述操作结束后点击运行即可。结束后会发现视频和评论已经尽数解决。如果有没看完或者没有评论完的情况大概率是numlist设置的范围小了。
原理分析及代码优化
只想完成任务的小伙伴已经可以下课了。
本地浏览器观看视频,发送评论在本质上是和雨课堂服务器进程进行交互,方式就是通过发送特定帧格式的数据包。我们的思路就是通过开发者工具获取对应数据包的帧格式和相应列表元素的具体值,伪造出一个真实的数据包,在本地进行发送,这就可以达到刷视频和刷评论的效果。
如何定位关键数据包
视频
对于视频而言,我们可以在播放视频的同时观察工具栏的“网络”窗口有什么变化,大致的发现是每隔一个固定的时间段会有新的数据包发送,而且是重名的。如下图所示
载荷就是这个数据包的具体内容,预览就是你把这个数据包发给服务器后它给你的反馈的具体内容。上图中的heartbeat/就是在观看视频时本地浏览器向雨课堂服务器发送的关键数据,即是在向服务器告知现在你正在学习这个视频,服务器收到这个数据包后就会在后台更新你的完成度。我们只需在本地模拟这个发包的过程即可,必须在本地完整地复刻上图数据包的完整信息,这样发送才能成功。
对于每一个视频上面呈现的每一个数据可能都不一样,不能每次都在这里面找然后复制到代码里去,这种操作还不如看视频。我们需要服务器给我们一个反馈的数据包里面包含我们需要的信息,这个操作也需要先通过向他发某种特定数据,我们才能读到反馈。如下图
上面这个数据包是在我们从学习日志点进某一个具体的视频(这里的视频编号是15743042)后会发送的一个数据包,服务器接收到后会反馈一些具体的视频信息。比如比较好懂的duration是时长。通过看heartbeat/里面有哪些需要的数据能和上图的信息对的上,直接复制即可。
评论
评论的原理和视频类似,而且比视频简单。点击“发送”其实就是在向后台发你的评论。具体过程不再赘述。只是评论模板比较单一,不可能根据问题描述去生成更合适的答案(如果能引入人工智能当我没说),因此会出现牛头不对马嘴的情况。有需要的话可以自行在py文件里面修改。
刷题
刷题未能实现的最大问题在于不能自动获取题目的正确答案(总不能刷完都是错的那不跟没刷一样吗)。而且答案只能提交一次,所以不能通过乱发然后获取正确答案去二次提交。大概的思路是发送一些不合法的数据包,在不更新作答情况的前提下骗取服务器的正确答案过来再提交。我先后考虑过几种特殊的数据包格式去试错:
将answer的内容置为空列表,但返回结果如下:
{"msg"
"\u65e0\u6548\u7684\u53c2\u6570:[]","error_.code":20002,"data":[),
"success":false}
将msg从unicode字符转化为中文后表示参数有误,这种格式的数据包是不接受的
将answer内容置为答案以外的字符,比如当前只能选A,B,C,D,我发个1过去
{"msg":"""data":{"count":1,"is show answer":true,"my score":0.0,"my count":1,"my answers":{"1":false},"is correct":false}
success":true}
发送虽然成功了但是直接给我判错了,很遗憾
可行的方法可能就是提前准备好每道题的答案,发送请求的时候直接找对应题号的答案就可以了。但是比较鸡肋,我要有答案了还何必写进这个脚本呢,不如直接用手交来的方便。
相关的优化
两篇作者都提出在进入某一个课程的时候会把整个要学习的目录以数据包的形式发过来,那学习对象的编号自然而言就在里面了,但是我找了以下只发现了部分数据如下图:
很明显我要看的视频都不止这么点吧。索性我干脆也不去扒这部分数据了,采用类似泛洪的思想,向从开头到结尾每一个编号都发送类似的“点击”请求,如果没有对应编号的任务会返回“Objects does not exit.",据此原理直接跳过即可。
至于如何区分当前任务是视频还是数据,可以对比点击后返回来的数据包的具体内容,可以发现的是视频的leaf_id=0,而评论的leaf_id=4.如果后期对作业有新的解决办法的话,它的leaf_id为6,可以直接通过这个键值来区分不同的任务类型,不用特定去生成一些videolist,commentlist和problemlist去保存对应的编号