├── .idea ├── .gitignore ├── compiler.xml ├── inspectionProfiles │ └── Project_Default.xml ├── jarRepositories.xml ├── misc.xml └── vcs.xml ├── pom.xml ├── readme.md ├── signscript.iml └── src └── main └── java └── per └── lx ├── Encrypt.java ├── Script.java ├── Utils.java └── XxtApi.java /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /../../../../:\MyProject\signscript\.idea/dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 36 | -------------------------------------------------------------------------------- /.idea/jarRepositories.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 9 | 10 | 14 | 15 | 19 | 20 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.lx 8 | signscript 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 8 13 | 8 14 | 15 | 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-web 20 | 2.7.2 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-logging 25 | 26 | 27 | 28 | 29 | 30 | commons-codec 31 | commons-codec 32 | 1.11 33 | 34 | 35 | 36 | com.alibaba 37 | fastjson 38 | 2.0.3 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-maven-plugin 49 | 50 | 51 | 52 | repackage 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## signscript 2 | 3 | ### 项目介绍 4 | 5 | 该脚本可用于超星学习通的 **位置签到** 与 **二维码签到**,位置签到可无视你当前的位置,二维码签到可无视二维码刷新时间。 6 | 7 | ### 项目运行 8 | 9 | #### 使用说明(科班版) 10 | 11 | 12 | 1. 在电脑上安装 jdk1.8 的运行环境 13 | 2. [点我下载脚本](https://gitee.com/huihui_lx/resource/raw/master/signscript.jar) 14 | 3. 运行脚本 signscript.java 文件 15 | 16 | #### 使用说明 (小白版) 17 | 18 | 1. 安装 jdk 1.8。(不会的就用搜索引擎搜一下, 然后跟着教程安装。大致用这样的话术搜索就 OK 了 “xxx(你的操作系统版本,比如win10, win11)安装 jdk1.8”) 19 | 20 | 2. [点我下载脚本](https://gitee.com/huihui_lx/resource/raw/master/signscript.jar) 21 | 22 | 3. 在文件夹中找到该脚本对应的目录, 在上面输入 cmd 然后回车。如下图: 23 | 24 | ![](https://gitee.com/huihui_lx/resource/raw/master/1.jpg) 25 | ![](https://gitee.com/huihui_lx/resource/raw/master/2.jpg) 26 | 27 | 4. 使用 **java -jar xxxx(脚本名)**, 比如脚本名为 signscript.java, 则执行 **java -jar signscript.java** 命令, 即可运行脚本。如图: 28 | 29 | ![](https://gitee.com/huihui_lx/resource/raw/master/3.jpg) 30 | 31 | ### 签到流程 32 | 33 | 1. 根据提示输入账号和密码。**注意:账号是能够登录学习通的手机号,不能是学号或是其他账号**,所以在使用前请保证 **能用该手机号和密码登录你的学习通** 34 | 2. **位置签到**,需要输入**经纬度**, [点我进入百度坐标拾取系统](https://api.map.baidu.com/lbsapi/getpoint/),将你要签到地点的经纬度复制下来,**注意:直接复制即可, 不要更改格式**。然后按提示输入姓名和地址,姓名填真实姓名即可, 这是显示在老师后台的签到人姓名。 位置填老师让你签到的位置, 比如“XXX大学XXX教学楼”, 这也是展示在老师后台你签到位置的文字信息。得到 success 提示即签到成功。 35 | 3. **二维码签到**, 先得到一张签到二维码,然后 [点我进入二维码解码器](https://cli.im/deqr),将二维码进行解码得到一个链接。**将链接中 enc= 和 & 中间的一串32位字符串复制下来**, 这就是 enc,按提示输入 enc。然后按提示输入姓名。得到 success 提示即签到成功。 36 | 37 | ### 注意事项 38 | 39 | 1. 每次只能签最近的一次签到。若短时间内有两个签到,在你签完了最新的签到之后,在这个最新的签到任务过期之前无法签这个任务之前的签到任务。比如:你在10:00,和 10:05 各有一个签到任务,而你在 10:06 才去用脚本签到,那么此时会对 10:05 的这个任务进行签到,在这个签到任务过期之前,无法对 10:00 的这个签到任务进行签到。 40 | 41 | ### 附 42 | 43 | + 大学时代,最值钱的是时间,最不值钱的也是时间。脚本虽好,望大家理智使用。 44 | + 如有任何问题,可提 issue。或者通过 1652020353@qq.com 联系我。 45 | + [点击此链接课访问在线版](http://47.98.160.201/),我给大家提供了一次签到机会,根据使用说明可在网站上完成签到。你们也可以参照脚本的源代码,自己写几个后台接口,写一个简单的前端页面,然后丢在服务器上运行。 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /signscript.iml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /src/main/java/per/lx/Encrypt.java: -------------------------------------------------------------------------------- 1 | package per.lx; 2 | 3 | import org.apache.commons.codec.binary.Hex; 4 | 5 | import javax.crypto.Cipher; 6 | import javax.crypto.SecretKeyFactory; 7 | import javax.crypto.spec.DESKeySpec; 8 | import java.security.Key; 9 | 10 | public class Encrypt { 11 | private static final String ALGORITHM = "DES"; 12 | private static final String CIPHER_ALGORITHM = "DES/ECB/PKCS5Padding"; 13 | private static final String CHARSET = "utf-8"; 14 | 15 | private Key generateKey(String password) throws Exception { 16 | DESKeySpec dks = new DESKeySpec(password.getBytes(CHARSET)); 17 | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(ALGORITHM); 18 | return keyFactory.generateSecret(dks); 19 | } 20 | 21 | public String encrypt(String password, String data) { 22 | if (password== null || password.length() < 8) { 23 | throw new RuntimeException("加密失败,key不能小于8位"); 24 | } 25 | if (data == null) { 26 | return null; 27 | } 28 | 29 | try { 30 | Key secretKey = generateKey(password); 31 | Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); 32 | cipher.init(Cipher.ENCRYPT_MODE, secretKey); 33 | byte[] bytes = cipher.doFinal(data.getBytes(CHARSET)); 34 | return Hex.encodeHexString(bytes); 35 | 36 | } catch (Exception e) { 37 | e.printStackTrace(); 38 | return data; 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/per/lx/Script.java: -------------------------------------------------------------------------------- 1 | package per.lx; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONArray; 5 | import com.alibaba.fastjson.JSONObject; 6 | import org.springframework.http.ResponseEntity; 7 | 8 | import java.util.List; 9 | import java.util.Scanner; 10 | 11 | public class Script { 12 | public static void main(String[] args) { 13 | Scanner scanner = new Scanner(System.in); 14 | 15 | String account, password; 16 | System.out.println("---请输入你的账号---"); 17 | account = scanner.nextLine(); 18 | System.out.println("---请输入你的密码---"); 19 | password = scanner.nextLine(); 20 | password = new Encrypt().encrypt("u2oh6Vu^HWe40fj", password); 21 | 22 | //登录 23 | ResponseEntity loginEntity = Utils.login(account, password); 24 | 25 | String body = loginEntity.getBody(); 26 | 27 | int indexStatus = body.indexOf("status"); 28 | String status = body.substring(indexStatus + 8, indexStatus + 13); 29 | 30 | if ("false".equals(status)) { 31 | System.out.println("用户登录失败, 账号或者密码错误"); 32 | return; 33 | } 34 | 35 | List cookies = loginEntity.getHeaders().get("Set-Cookie"); 36 | 37 | //查找所有课程 38 | String courses = Utils.findCourses(cookies); 39 | 40 | while (true) { 41 | int start = courses.indexOf("courseId"); 42 | if (start == -1) { 43 | break; 44 | } 45 | String courseId = courses.substring(start + 9, start + 18); 46 | 47 | start = courses.indexOf("classId"); 48 | if (start == -1) { 49 | break; 50 | } 51 | String classId = courses.substring(start + 8, start + 16); 52 | 53 | courses = courses.substring(start + 17); 54 | 55 | //查找所有活动 56 | String content = Utils.getActiveList(courseId, classId, cookies).getBody(); 57 | JSONObject jsonObject = JSONObject.parseObject(content); 58 | if (jsonObject.get("data") == null) { 59 | continue; 60 | } 61 | JSONObject data = JSONObject.parseObject(jsonObject.get("data").toString()); 62 | JSONArray activeList = JSONObject.parseArray(data.get("activeList").toString()); 63 | 64 | for (int i = 0; i < activeList.size(); i++) { 65 | JSONObject obj = activeList.getJSONObject(i); 66 | //活动id 67 | String otherId = ""; 68 | if (obj.get("otherId") != null) { 69 | otherId = obj.get("otherId").toString(); 70 | } 71 | String activeId = obj.get("id").toString(); 72 | String activeStatus = obj.get("status").toString(); 73 | if ("4".equals(otherId) && "1".equals(activeStatus)) { 74 | System.out.println("---查到了一个位置签到---"); 75 | System.out.println("---请输入经纬度----"); 76 | String coordinate = scanner.nextLine(); 77 | 78 | int index = coordinate.indexOf(","); 79 | String longitude = coordinate.substring(0, index), latitude = coordinate.substring(index + 1); 80 | 81 | System.out.println("---请输入姓名---"); 82 | String name = scanner.nextLine(); 83 | System.out.println("---请输入地址---"); 84 | String address = scanner.nextLine(); 85 | Utils.preSign(activeId, cookies); 86 | //位置签到 87 | String pptSign = Utils.pptSign(latitude, longitude, activeId, name, address, cookies); 88 | System.out.println(pptSign); 89 | return; 90 | 91 | } else if ("2".equals(otherId) && "1".equals(activeStatus)) { 92 | System.out.println("---查到了一个二维码签到---"); 93 | System.out.println("---输入enc---"); 94 | String enc = scanner.nextLine(); 95 | System.out.println("---输入姓名---"); 96 | String name = scanner.nextLine(); 97 | Utils.preSign(activeId, cookies); 98 | //二维码签到 99 | String qrCodeSign = Utils.QRCodeSign(enc, name, activeId, cookies); 100 | System.out.println(qrCodeSign); 101 | return; 102 | }else if("0".equals(otherId) && "1".equals(activeStatus)) { 103 | System.out.println("---查到了一个普通签到---"); 104 | System.out.println("开始为您签到..."); 105 | String ordinarySign = Utils.OrdinarySIGN(activeId, cookies); 106 | JSONObject jsonObject1 = JSON.parseObject(ordinarySign); 107 | String msg = jsonObject1.get("msg").toString(); 108 | System.out.println(msg); 109 | return; 110 | } 111 | } 112 | } 113 | System.out.println("无签到课程"); 114 | } 115 | } -------------------------------------------------------------------------------- /src/main/java/per/lx/Utils.java: -------------------------------------------------------------------------------- 1 | package per.lx; 2 | 3 | import org.springframework.http.HttpEntity; 4 | import org.springframework.http.HttpHeaders; 5 | import org.springframework.http.HttpMethod; 6 | import org.springframework.http.ResponseEntity; 7 | import org.springframework.util.LinkedMultiValueMap; 8 | import org.springframework.util.MultiValueMap; 9 | import org.springframework.web.client.RestTemplate; 10 | 11 | import java.util.HashMap; 12 | import java.util.List; 13 | import java.util.Map; 14 | 15 | public class Utils { 16 | static RestTemplate restTemplate = new RestTemplate(); 17 | 18 | public static ResponseEntity login(String account, String password) { 19 | HttpHeaders headers = new HttpHeaders(); 20 | 21 | MultiValueMap map = new LinkedMultiValueMap<>(); 22 | map.add("fid", -1); 23 | map.add("uname", account); 24 | map.add("password", password); 25 | map.add("refer", "http%253A%252F%252Fi.chaoxing.com"); 26 | map.add("t", true); 27 | map.add("forbidotherlogin", 0); 28 | map.add("validate", null); 29 | map.add("doubleFactorLogin", 0); 30 | HttpEntity> request = new HttpEntity(map, headers); 31 | 32 | ResponseEntity entity = restTemplate.postForEntity(XxtApi.LOGIN, request, String.class); 33 | return entity; 34 | } 35 | 36 | public static String findCourses(List cookies) { 37 | HttpHeaders headers = new HttpHeaders(); 38 | headers.put(HttpHeaders.COOKIE, cookies); 39 | MultiValueMap params = new LinkedMultiValueMap<>(); 40 | HttpEntity> httpEntity = new HttpEntity<>(params, headers); 41 | ResponseEntity responseEntity = restTemplate.exchange(XxtApi.FIND_COURSE, HttpMethod.GET, httpEntity, String.class); 42 | 43 | return responseEntity.toString(); 44 | 45 | } 46 | 47 | //查找活动 48 | public static ResponseEntity getActiveList(String courseId, String classId, List cookies) { 49 | String url = XxtApi.GET_ACTIVE_LIST + courseId + "&classId=" + classId + "&showNotStartedActive=0"; 50 | Map params = new HashMap<>(); 51 | params.put("fid", -1); 52 | params.put("courseId", courseId); 53 | params.put("classId", classId); 54 | params.put("showNotStartedActive", 0); 55 | 56 | HttpHeaders headers = new HttpHeaders(); 57 | headers.put(HttpHeaders.COOKIE, cookies); 58 | Map paramMap = new HashMap<>(); 59 | HttpEntity> httpEntity = new HttpEntity<>(paramMap, headers); 60 | 61 | ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); 62 | return responseEntity; 63 | } 64 | 65 | public static void preSign(String activeId, List cookies) { 66 | String url = XxtApi.PRE_SIGN + activeId; 67 | HttpHeaders headers = new HttpHeaders(); 68 | headers.put(HttpHeaders.COOKIE, cookies); 69 | Map paramMap = new HashMap<>(); 70 | HttpEntity> httpEntity = new HttpEntity<>(paramMap, headers); 71 | restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); 72 | } 73 | 74 | //位置签到 75 | public static String pptSign(String latitude, String longitude, String activeId, String name, String address, List cookies) { 76 | String url = XxtApi.LOCATION_SIGN + name + "&address=" + address + "&activeId=" + activeId + "&latitude=" + latitude + "&longitude=" + longitude; 77 | HttpHeaders headers = new HttpHeaders(); 78 | headers.put(HttpHeaders.COOKIE, cookies); 79 | Map paramMap = new HashMap<>(); 80 | HttpEntity> httpEntity = new HttpEntity<>(paramMap, headers); 81 | ResponseEntity entity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); 82 | return entity.getBody(); 83 | } 84 | 85 | public static String QRCodeSign(String enc, String name, String activeId, List cookies) { 86 | String url = XxtApi.QRCODE_SIGN + enc + "&name=" + name + "&activeId=" + activeId + "&clientip=&useragent=&latitude=-1&longitude=-1&appType=15 "; 87 | HttpHeaders headers = new HttpHeaders(); 88 | headers.put(HttpHeaders.COOKIE, cookies); 89 | Map paramMap = new HashMap<>(); 90 | HttpEntity> httpEntity = new HttpEntity<>(paramMap, headers); 91 | ResponseEntity entity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); 92 | return entity.getBody(); 93 | } 94 | 95 | public static String OrdinarySIGN(String activeId, List cookies) { 96 | String url = XxtApi.Ordinary_SIGN + activeId; 97 | HttpHeaders headers = new HttpHeaders(); 98 | headers.put(HttpHeaders.COOKIE, cookies); 99 | Map paramMap = new HashMap<>(); 100 | HttpEntity> httpEntity = new HttpEntity<>(paramMap, headers); 101 | ResponseEntity entity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class); 102 | return entity.getBody(); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/per/lx/XxtApi.java: -------------------------------------------------------------------------------- 1 | package per.lx; 2 | 3 | public interface XxtApi { 4 | String LOGIN = "http://passport2.chaoxing.com/fanyalogin"; 5 | String FIND_COURSE = "https://mooc1-api.chaoxing.com/mycourse/backclazzdata?view=json&mcode="; 6 | String GET_ACTIVE_LIST = "https://mobilelearn.chaoxing.com/v2/apis/active/student/activelist?fid=-1&courseId="; 7 | String PRE_SIGN = "https://mobilelearn.chaoxing.com/newsign/preSign?activePrimaryId="; 8 | String LOCATION_SIGN = "https://mobilelearn.chaoxing.com/pptSign/stuSignajax?name="; 9 | String QRCODE_SIGN = "https://mobilelearn.chaoxing.com/pptSign/stuSignajax?enc="; 10 | String Ordinary_SIGN = "https://mobilelearn.chaoxing.com/v2/apis/sign/signIn?activeId="; 11 | } --------------------------------------------------------------------------------