趁着周末有空,最近又在做爬虫相关的功能,就研究了一下强智教务系统,模拟登录,在登录成功后得到学号、姓名、学院等信息。将写好的Demo也一起放在了码云。
码云地址:https://gitee.com/palewl/spder_pz_login
广告:
个人博客,网页版:palewl.cn
小程序端:培正Lite
使用技术:java为前提,使用HttpClient和Jsoup。
使用工具:结合psotMan进行测试
以广东培正学院强智教务系统为例:http://qzjw.peizheng.edu.cn/jsxsd/
嗯,只有一个账户框和密码框,不需要去处理验证码。试着输入学号密码等,打开F12调试
需要找到一个叫 LoginToXk的请求,这个是登录的POST请求,把登录信息提交后都在这里处理请求,成功后就会重定向到后台正确的地址。
往下翻,可以找到账户和密码的key值
需要的两个值的名称都有了。
请求地址:http://qzjw.peizheng.edu.cn/jsxsd/xk/LoginToXk
请求方式:PSOT
分别为:userAccount 、userPassword
还有一个不知道用途的 encoded
当然,我们还需要找一个后台的正确地址,因为这个仅仅是判断登录信息的POST请求,当请求成功之后后台就会重定向到强智教务系统的个人中心。
继续F12找,找到请求: xsMain_new.jsp?t1=1,调到Response,查看响应结果。
要的信息都在这个请求了。
请求地址:http://qzjw.peizheng.edu.cn/jsxsd/framework/xsMain_new.jsp?t1=1
请求方式:GET
既然要的信息都有了,先用PostMan来测试一下,如果PostMan测试通过的话那写代码才是正确的,如果PostMan都无法成功,那就肯定不行的。
步骤:
1.根据账户密码,去发起登录请求
请求地址:http://qzjw.peizheng.edu.cn/jsxsd/xk/LoginToXk
请求方式:PSOT
2.因为强智还使用的JSP,所以基本都是 后端Session来存储用户信息,浏览器存入用户的cookie,在下一次请求当中将Cookie放入请求头。
此处找到PostMan的heade信息:找到Set-Cookie
3.如果登录成功的话,这一串就是后端返回的Cookie信息了。
拿到这个信息去继续请求:
请求地址:http://qzjw.peizheng.edu.cn/jsxsd/framework/xsMain_new.jsp?t1=1
请求方式:GET
但是结果…
返回来的信息,我仔细的对比了一下,跟登录页面是一模一样的。
失败了。
基本思路是没有问题的,所以可能是漏了什么参数,或者是登录机制是采用了别的验证方式。
继续查看重定向的参数:
此处的encoded很可疑。
可以看到
encoded的值是经过加密的,加密的方法为encodeInp(obj)
推测就是此处的参数没明白,所以失败。
继续查看,发现encodeInp(obj)方法在一个js里,具体的处理加密机制在common.js
但是:
这个encoded的 = ,之前貌似看过是Base64的加密方式。
找一个base64在线加密试了一下,确实是这个。
行,一模一样。
为了测试方便,我把在浏览器的encoded复制到postman,结果证明这个尝试是正确的,这里就不演示了。
1.创建一个maven工程,导入坐标
<!--Jsoup-->
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.10.3</version>
</dependency>
<!--Lang3工具类-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<!--HttpClient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.6</version>
</dependency>
<!--阿里巴巴 json-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.51</version>
</dependency>
准备工具类用于进行Base64加密。
package com.xiaomoyu.pz.utils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
/**
* 基于Base64的加密和解密工具类
*/
public class Base64EncodeUtils {
/**
* 示例使用
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception {
String str = "学号";
String pass = "密码";
String username = encryptBASE64(str.getBytes());
String password = encryptBASE64(pass.getBytes());
System.out.println(username+"%%%"+password);
}
/**
* BASE64解密
* @throws Exception
*/
public static byte[] decryptBASE64(String key) throws Exception {
return (new BASE64Decoder()).decodeBuffer(key);
}
/**
* BASE64加密
*/
public static String encryptBASE64(byte[] key) throws Exception {
return (new BASE64Encoder()).encodeBuffer(key);
}
}
登录方法:
package com.xiaomoyu.pz;
import com.xiaomoyu.pz.utils.Base64EncodeUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 登录
*/
public class LoginPz {
public static void main(String[] args) {
Map<String,String> param = new HashMap<>();
String userAccount = "输入你的账户";
String userPassword = "输入你的密码";
String encoded = "";//加密信息
try {
encoded = Base64EncodeUtils.encryptBASE64(userAccount.getBytes()) +"%%%"+Base64EncodeUtils.encryptBASE64(userPassword.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
param.put("userAccount",userAccount);
param.put("userPassword",userPassword);
param.put("encoded",encoded);
List<URI> redirectLocations = null;
// 创建Httpclient对象
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse response = null;
String resultString = "";
try {
// 创建Http Post请求
HttpPost httpPost = new HttpPost("http://qzjw.peizheng.edu.cn/jsxsd/xk/LoginToXk");
//请求头
httpPost.addHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
httpPost.addHeader("Cookie","application/x-www-form-urlencoded; charset=UTF-8");
// 创建参数列表
if (param != null) {
List<NameValuePair> paramList = new ArrayList<>();
for (String key : param.keySet()) {
paramList.add(new BasicNameValuePair(key, param.get(key)));
}
// 模拟表单登录
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
httpPost.setEntity(entity);
}
// 执行http请求
HttpClientContext context = HttpClientContext.create();
response = httpClient.execute(httpPost,context);
//获取Cookie信息,得到两个参数 JSESSIONID 、 BIGipServerpool_qzjw
List<Cookie> cookies = context.getCookieStore().getCookies();
for (Cookie cookie : cookies) {
String name = cookie.getName();
String value = cookie.getValue();
System.out.println("name:"+name+","+value);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
response.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
为了方便,都写在主方法当中。
当运行这个方法时,可以得到两个参数:
JSESSIONID 、 BIGipServerpool_qzjw
有了这两个参数,就相当于有了强智服务器识别你身份的钥匙,后续需要的各种操作,如查成绩,查信息,查课表,抢课,考勤等都可以使用。
只需要再后续的操作中,加入到请求头即可。
得到 JSESSIONID 、 BIGipServerpool_qzjw后的使用实例:
注意此处需要修改JSESSIONID 、和 BIGipServerpool_qzjw
package com.xiaomoyu.pz;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;
/**
* 登录后获取用户信息
* 相关解析HTMl的操作不是固定的
* 需要结合自己的需求来操作
* 此处仅作为演示。
*/
public class GetUserInfo {
public static void main(String[] args) {
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
HttpGet httpGet = new HttpGet("http://qzjw.peizheng.edu.cn/jsxsd/framework/xsMain_new.jsp?t1=1");
//增加头信息
//注意此处需要修改为正确的JSESSIONID 和 BIGipServerpool_qzjw
httpGet.addHeader("Cookie","JSESSIONID=; BIGipServerpool_qzjw=");
httpGet.addHeader("User-Agent","Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36");
httpGet.addHeader("Accept","text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9");
httpGet.addHeader("Connection","keep-alive");
//执行
CloseableHttpResponse response = httpClient.execute(httpGet);
String html = EntityUtils.toString(response.getEntity(), "utf8");
System.out.println("结果:"+html);
//解析html
Document parse = Jsoup.parse(html);
Elements select = parse.select("div.middletopttxlr");
Elements select1 = select.select("div.middletopdwxxcont");
String text = select1.text();
String[] s = text.split(" ");
String name = s[1];//姓名
String studentId = s[2];//学号
String department = s[3];//院系
String major = s[4];//专业
String stClass = s[5];//班级
System.out.println(name+","+studentId+","+department+","+major+","+stClass);
}catch (Exception e){
}
}
}