对某班题库api的技术分析
因为某种原因需要在易班上进行练习校规校纪,非常好的平台,非常非常好。嗯~
作为社会主义接班人,当代优秀大学生,这么好的题不存下来慢慢学习,对不起自己,对不去社会啊!!!
然后默默的按下了f12,开发者模式
然后界面如下
然后seach 一下ajax,发现4个api
1./t/student/updateTraining
2./t/student/collectshiti
3./t/student/showMobileLSjAjax
4./t/student/errorfeedback
按照这个网页的设计的思路来讲,肯定有个报错反馈的api,肯定有个更新试题的api,有个加载页面基础布局的api
然后盲猜一波,
第一个api是请求试题,因为update 更新 traning 训练。嗯~就差不多了
第四个,带着error,那就是错误反馈
第二个 收集 shiti????(疯狂吐槽命名)。根据api所在上下文应该是收藏试题用的,就是收藏然后再次登录的时候错题本之类的就会有,嗯~,就先这样
第三个不知道干啥了emmm
盲猜完毕,开始检验,使用抓包工具,开始抓包
事实证明,盲从错误,啪啪打脸
/t/student/showMobileLSj是加载页面的
哪我们的目标是数据数据在哪?,当我重新刷新的时候,抓到两个包,第一个就是上面那个
第二个如下
wow~数据在这/t/student/showMobileLSjAjax
哪我们重新理一下思路。
当我们点击题库连接时,发生了什么???
第一步初始化,初始化的时候先访问/t/student/showMobileLSj,加载基本布局,
随后访问/t/student/showMobileLSjAjax,加载数据,这样初始化完成
然后静默,等待用户操作,
如果出错访问/t/student/errorfeedback,
如果收藏访问/t/student/collectshiti,
如果刷新,访问/t/student/showMobileLSjAjax。
至于这个/t/student/updateTraining懒得管了。
数据分析
数据传回来是个json字符串,从外往里面来吧
最外面是statu msg 和date 嗯就是返回的格式,statu为状态码,msg为提示信息 date 为数据体,顺便说一句,这种形式很常见,后端就是一个dtoresponse这样的类,这样写的好处多多
然后看data
然后就是英文理解了,继续盲猜
collageid 学校的id
examtype 后面跟的一个应该是枚举的值,现在是1应该就是刷题模式
剩下的有时间慢慢猜
然后是data的对象一个是getshijuaninfor(吐槽命名)
没大用对于我们的目的
然后就是shitilist,emmm
本人非常好奇第一个的加密字符串,但是无奈不会解密啊
然后里面有的就是题和答案,答案在old_answer里面,俺不知道为啥叫 old answer
我们的目标数据完成了,也就不看了
下面分析api
api的分析
就是分析这个/t/student/showMobileLSjAjax
首先是参数,分析也不算分析,就是抄嘛!抄啥?当然是抓的包啦
四个参数,不巧上面的数据里面都有,就这个page ,然后多看几道题,发现就是随着题目的位置变化的,由上文可知,一共171道题,那么page的范围就是1-171的整数。
然后进行测试,使用postman,
测试注意的地方
我们是模拟发送请求,那么服务器一定要校验我们的请求是不是合法,对于这种请求,是一定要登录之后才能进行操作的,所以把网页的cookie 复制到herder里面。其余参数用formdate
测试成功。
个人感觉还有别的方法可以申请到试题
程序控制访问171次
这里采用c#演示
static void Main(string[] args)
{
Console.WriteLine("*****正在开始*****");
for (int i = 1; i < 171; i++)
{
Console.WriteLine("正在开始第{0}个数据",i+1);
Console.WriteLine("");
Console.WriteLine("onloading!!!");
var date = GetShiti(i + 1);
WriteShiti(date);
//我们是正经技术分析,不是攻击,所以速度放慢
Thread.Sleep(800);
Console.WriteLine("************************");
}
}
public static Rootobject GetShiti(int num)
{
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.Add("courseid", "13036");
dic.Add("coursename", "校规校纪题库");
dic.Add("id", "13036");
dic.Add("page", num.ToString());
//请求头处理
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.yiban.cn/t/student/showMobileLSjAjax");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
request.Headers.Add("Cookie", "");
#region 添加Post 参数
StringBuilder builder = new StringBuilder();
int i = 0;
foreach (var item in dic)
{
if (i > 0)
builder.Append("&");
builder.AppendFormat("{0}={1}", item.Key, item.Value);
i++;
}
byte[] data = Encoding.UTF8.GetBytes(builder.ToString());
request.ContentLength = data.Length;
using (Stream reqStream = request.GetRequestStream())
{
reqStream.Write(data, 0, data.Length);
reqStream.Close();
}
#endregion
var resp = request.GetResponse();
//获取响应内容
string result = string.Empty;
using (StreamReader reader = new StreamReader(resp.GetResponseStream(), Encoding.UTF8))
{
result = reader.ReadToEnd();
};
Console.WriteLine(result);
string json = result;
result += "\r\n";
result += "---分隔符---";
WriteFile("jsondate.txt", result);
return JsonConvert.DeserializeObject<Rootobject>(json);
}
public static void WriteShiti(Rootobject item)
{
string shiti = string.Empty;
for (int i = 0; i < item.data.shitilist.Length; i++)
{
shiti += Encoding.Unicode.GetString(Encoding.Unicode.GetBytes(item.data.shitilist[i].title));
shiti += "\r\n";
for (int j = 0; j < item.data.shitilist[i].options.Length; j++)
{
shiti+= Encoding.Unicode.GetString(Encoding.Unicode.GetBytes(item.data.shitilist[i].options[j]));
shiti += "\r\n";
}
string[] oldanwer = item.data.shitilist[i].old_answer.Split(',');
for (int k = 0; k < oldanwer.Length; k++)
{
switch (oldanwer[k])
{
case "1":
shiti += "A";
break;
case "2":
shiti += "B";
break;
case "3":
shiti += "C";
break;
case "4":
shiti += "D";
break;
case "5":
shiti += "E";
break;
}
}
shiti += "\r\n";
shiti += "*****************************************************";
shiti += "\r\n";
WriteFile("shiti.txt", shiti);
}
}
public static void WriteFile(string path,string content)
{
Console.WriteLine("开始写入文件");
FileStream fs = null;
string filePath = path;
//将待写的入数据从字符串转换为字节数组
Encoding encoder = Encoding.UTF8;
byte[] bytes = encoder.GetBytes(content);
try
{
fs = File.OpenWrite(filePath);
//设定书写的開始位置为文件的末尾
fs.Position = fs.Length;
//将待写入内容追加到文件末尾
fs.Write(bytes, 0, bytes.Length);
Console.WriteLine("写入文件完成");
}
catch (Exception ex)
{
Console.WriteLine("文件打开失败{0}", ex.ToString());
}
finally
{
fs.Close();
}
}
这样就把所有的题目给扒了下来。
我们算一下时间成本,单纯的扒题
两种方式,第一种就是复制黏贴,熟读快的话20s一个题,171个题,差不多也就是50min
第二种方式就是这样敲代码,我写了差不多两个小时吧emmm是有点慢。
我们只是为了把题存下来以后继续好好学习,看样子还是第一种比好好,所以大家还是复制黏贴扒题吧!
本文只是技术交流,如若用于不合规方面,后果自负