聲明 這個程式只是用來演示查看後臺和對接後臺的原理和過程,供代碼學習參考,請勿濫用! 起因 因為上海疫情,我們所有的活動都得線上上完成,作為一個新時代好學生,我該做點什麼了。 我的學校選擇的上課平臺是希沃的立知課堂,教師端是希沃白板電腦客戶端,學生端是網頁端、微信小程式端、移動設備軟體端。 觀察後臺 ...
聲明
這個程式只是用來演示查看後臺和對接後臺的原理和過程,供代碼學習參考,請勿濫用!
起因
因為上海疫情,我們所有的活動都得線上上完成,作為一個新時代好學生,我該做點什麼了。
我的學校選擇的上課平臺是希沃的立知課堂,教師端是希沃白板電腦客戶端,學生端是網頁端、微信小程式端、移動設備軟體端。
觀察後臺
一看到網頁端,就說明可以用F12查找後臺,那麼我破解前期,就做了觀察
這一個工作。
用了大概兩天時間,找到了主要的兩個後臺:
/*
後文將此API稱為:Api I
這個後臺被官方用來獲取課件略縮圖,因為可以調整解析度,所以就能用來瀏覽課件。
這個後臺無需Cookies
需要通過GET方式傳遞數據, 等於號後的是實例數據:
1. 課件ID: coursewareId=xxxx-xxxx-xxxx-xxxxxxx
2. 課件版本: version=19
3. 返回圖片的解析度: resolution=960_640
以上所有欄位必須需傳遞
*/
GetCoursewareApi = "https://s2.imlizhi.com/slive/pc/enow/thumbnail/api/v1/courseware";
/*
後文將此API稱為:Api II
這個後臺被官方用來獲取課件列表和所需數據,為了能準確獲取課件ID等信息,需要用到這個後臺。
這個後臺需要立知的Cookies
需要通過POST方式傳遞數據, 包含實例數據:
1. 教室的Uid '{"courseUid":"a57ee0d4f7fc4e39b0e95e3d53de2574"}'
所有欄位必須需傳遞
*/
var ServerTime = new Date().getTime();
GetCoursewareListApi = "https://s2.imlizhi.com/slive/pc/apis.json?actionName=GET_COURSE_ACCESS_CODE_LIST&t=" + ServerTime;
/*或者:*/
GetCoursewareListApi = "https://s.imlizhi.com/slive/pc/apis.json?actionName=GET_COURSE_ACCESS_CODE_LIST&t=" + ServerTime;
那怎麼實現呢?
選擇平臺
因為後臺需要使用Cookies,所以很難實現桌面客戶端。
原先想到瀏覽器擴展,但擴展只能用於同內核瀏覽器,且需要調用瀏覽器API介面,相容性不行還編起來難。
我選擇了以下兩種方案:
- Tampormonkey 油猴腳本
- 直接在瀏覽器書簽欄加入帶有JavaScript腳本的書簽,編起來簡單,也能獲取網站一切內容的訪問許可權,同時AJAX跨域的問題也能解決。
為了方便給讀者看到代碼實現原理,我選擇了後者。
(*註:為後者編寫的代碼可以快速地移植到前者,不需要改動代碼)
對接API
因為對接的後臺處於網頁教室的同目錄或子目錄,所以我使用了相對路徑。
先對接Api II
我使用了原生AJAX代碼進行POST數據傳遞:
獲取Uid
獲取courseUid的方法很簡單,下麵是網頁端教室鏈接:
https://s2.imlizhi.com/slive/pc/room?courseUid=534617396df542e0a09fd01f80e1ef2a&appCode=en-easilive
只需要用split,拿到courseUid即可。
var uid = window.location.href.split("?")[1].split("&")[0].split("=")[1];
獲取ServerTime
通過觀察,可以發現傳遞的t
對應以下代碼:
var ServerTime = new Date().getTime();
課件列表實現的完整代碼
function GetList(){
var uid = window.location.href.split("?")[1].split("&")[0].split("=")[1];
var ServerTime = new Date().getTime();
var xhttp = null;
if(window.XMLHttpRequest){xhttp = new XMLHttpRequest();}
else if(window.ActiveXObject){xhttp = new ActiveXObject('Microsoft.XMLHTTP');}
/*瀏覽器相容性*/
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var jstr = eval("(" + this.responseText + ")");
if(jstr["error_code"] == 0){
var OPStr = "";
for(var i = 0; i <= 10; i ++) {
try{ OPStr += (i + 1) + ". " + jstr.data[i].name + "\n"; } catch(e){}
}
let k = prompt("請選擇需要打開的課件(填數字編號)\n" + OPStr, "1");
//GetCourseware(jstr.data[k - 1].cid, jstr.data[k - 1].version);
} else {
alert("課程未開始或課程已結束!");
}
}
};
xhttp.open("POST", "./apis.json?actionName=GET_COURSE_ACCESS_CODE_LIST&t=" + ServerTime, true);
xhttp.setRequestHeader('Content-Type','application/json');
xhttp.send('{"courseUid":"' + uid + '"}');
}
再對接Api I
function GetCourseware(cid, ver){
var xhttp = null;
if(window.XMLHttpRequest){xhttp = new XMLHttpRequest();}
else if(window.ActiveXObject){xhttp = new ActiveXObject('Microsoft.XMLHTTP');}
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//ShowCourseware(this.responseText);
}
};
xhttp.open("GET", "./enow/thumbnail/api/v1/courseware?coursewareId=" + cid + "&version=" + ver + "&resolution=960_640", true);
xhttp.send();
}
最後將獲取的課件圖片列表輸出到瀏覽器新標簽頁
傳入的filelist是字元串類型,不是JSON
function ShowCourseware(filelist){
let dochtml = "";
let MaxPageNum = 200;
let PageCnt = 0;
let result = filelist;
let obj = [];
filelist = eval("("+result+")");
var win = window.open();
if(filelist.message != "error"){
for(var i = 0; i <= MaxPageNum; i ++){
try{ obj[filelist.data[i].pageIndex] = filelist.data[i].downloadUrl; }catch{}
}
for(i = 0; i <= MaxPageNum; i ++){
if(obj[i] != undefined) { dochtml += "<img src='" + obj[i] + "' title='第" + (i + 1) + "頁'><br>"; PageCnt += 1; }
}
var script = `<script>function printmode(){
document.getElementsByClassName("msg")[0].remove();
document.getElementsByTagName("style")[0].innerText = "img{width:100%;margin-top:15px;}";
}</script>`;
var header = `<title>課件瀏覽器</title>
<meta charset="utf-8">
<style>body{background-color: rgb(50, 54, 57); user-select: none;margin:0px;}
.ctrl{font-size:14px; border-radius:15px; padding:5px; padding-left:13px; padding-right:13px; background-color: rgb(51, 51, 51); color:#FFF; border:1px solid #CCC;}
.msg{position:fixed; top:15px; left:15px; z-index:5;} img{width:60%; min-width:600px; margin-top:10px; border-radius:4px;}
.printBtn{margin:10px;} a{color:#FFF; text-decoration:none;}</style>`;
var body = `<body>
<div class="ctrl msg">
共` + PageCnt + `頁
</div>
<center>` + dochtml + `<button onclick="this.remove();printmode();" class="ctrl printBtn">列印 & PDF存儲模式</button></center></body>`;
win.document.write(header + script + body);
} else {
win.document.write("<title>出現問題</title><h2>抱歉,無法為您獲取課件</h2><hr><b>你可以聯繫該課件的分享者,以取得解決方案。</b>");
}
}
我在裡面加入了 "列印&PDF" 存儲模式,方便使用Firefox、Chrome和Edge的PDF存儲模式將課件存為文件。
完整代碼
給大家加上完成後的代碼:
javascript:
function ShowCourseware(filelist){
dochtml = "";
MaxPageNum = 200;
PageCnt = 0;
result = filelist;
obj = [];
var filelist = eval("("+result+")");
var win = window.open();
if(filelist.message != "error"){
for(var i = 0; i <= MaxPageNum; i ++){
try{
obj[filelist.data[i].pageIndex] = filelist.data[i].downloadUrl;
}catch{}
}
for(i = 0; i <= MaxPageNum; i ++){
if(obj[i] != undefined) {dochtml += "<img src='" + obj[i] + "' title='第" + (i + 1) + "頁'><br>"; PageCnt += 1;}
}
var script = `<script>function printmode(){
document.getElementsByClassName("msg")[0].remove();
document.getElementsByTagName("style")[0].innerText = "img{width:100%;margin-top:15px;}";
}</script>`;
var header = `<title>課件瀏覽器</title>
<meta charset="utf-8">
<style>body{background-color: rgb(50, 54, 57); user-select: none;margin:0px;}
.ctrl{font-size:14px; border-radius:15px; padding:5px; padding-left:13px; padding-right:13px; background-color: rgb(51, 51, 51); color:#FFF; border:1px solid #CCC;}
.msg{position:fixed; top:15px; left:15px; z-index:5;} img{width:60%; min-width:600px; margin-top:10px; border-radius:4px;}
.printBtn{margin:10px;} a{color:#FFF; text-decoration:none;}</style>`;
var body = `<body>
<div class="ctrl msg">
共` + PageCnt + `頁
</div>
<center>` + dochtml + `<button onclick="this.remove();printmode();" class="ctrl printBtn">列印 & PDF存儲模式</button></center></body>`;
win.document.write(header + script + body);
} else {
win.document.write("<title>出現問題</title><h2>抱歉,無法為您獲取課件</h2><hr><b>你可以聯繫該課件的分享者,以取得解決方案。</b>");
}
}
function GetCourseware(cid, ver){
var xhttp = null;
if(window.XMLHttpRequest){xhttp = new XMLHttpRequest();}
else if(window.ActiveXObject){xhttp = new ActiveXObject('Microsoft.XMLHTTP');}
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
ShowCourseware(this.responseText);
}
};
xhttp.open("GET", "./enow/thumbnail/api/v1/courseware?coursewareId=" + cid + "&version=" + ver + "&resolution=960_640", true);
xhttp.send();
}
function GetList(){
var uid = window.location.href.split("?")[1].split("&")[0].split("=")[1];
var ServerTime = new Date().getTime();
var xhttp = null;
if(window.XMLHttpRequest){xhttp = new XMLHttpRequest();}
else if(window.ActiveXObject){xhttp = new ActiveXObject('Microsoft.XMLHTTP');}
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var jstr = eval("(" + this.responseText + ")");
if(jstr["error_code"] == 0){
var OPStr = "";
for(var i = 0; i <= 10; i ++) {
try{
OPStr += (i + 1) + ". " + jstr.data[i].name + "\n";
} catch{}
}
let k = prompt("請選擇需要打開的課件(填數字編號)\n" + OPStr, "1");
GetCourseware(jstr.data[k - 1].cid, jstr.data[k - 1].version);
} else {
alert("課程未開始或課程已結束!");
}
}
};
xhttp.open("POST", "./apis.json?actionName=GET_COURSE_ACCESS_CODE_LIST&t=" + ServerTime, true);
xhttp.setRequestHeader('Content-Type','application/json');
xhttp.send('{"courseUid":"' + uid + '"}');
}
GetList();
使用方法和最終效果
使用方法
- 將完整代碼複製
- 將本頁內容加入書簽欄(不要放在其他收藏夾)
- 右鍵加入的書簽,點擊“編輯”
- 名稱改為“破解”(其他名稱也沒問題)
- 刪除URL後的輸入框的內容,在裡面粘貼複製的代碼
- 點擊“完成”即可
最終效果
在教室內點擊剛纔加入的書簽,會彈出以下畫面,找到想要打開的課件,輸入對應序號,點擊確定。
看見課程列表:
這個程式只是用來演示查看後臺和對接後臺的原理和過程,供代碼學習參考,請勿濫用!
該文章並非轉載,只是我自己有一個CSDN的賬戶