0


基于selenium和HttpClient框架爬取南京工程学院教务系统学生成绩

文章目录

代码地址:
爬取官网成绩: 爬取官网成绩 (gitee.com)

获取到这个接口之后后序选课、课程表等功能都是可以完成的。

HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接,这就意味着服务器无法从连接上跟踪会话。也就是说即使第一次和服务器连接后并且登录成功后,第二次请求服务器依然不能知道当前请求是哪个用户。如何确定某一个用户呢?可以通过cookie。

第一次登录后服务器后,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个cookie,浏览器会把cookie数据保存在本地。该用户发送第二次请求的时候,就会自动的把上次请求存储的cookie数据自动的携带给服务器,服务器检查该cookie存储name,value等信息,以此来辨认用户状态,服务器还可以根据需要修改cookie的内容。

cookie就相当于是服务器给客户端们颁发一个通行证,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份,这就是Cookie的工作原理。

分析登录到首页和信息门户也,两次的cookie是不一样的。 首页的Cookie是比较多的

发送获取成绩接口的请求是登录到教务系统的cookie。

selenium

Selenium是一系列基于Web的自动化工具,提供一套测试函数,用于支持Web自动化测试。函数非常灵活,能够完成界面元素定位、窗口跳转、结果比较。具有如下特点:

使用这个框架需要配套 google浏览器和google driver 这两个版本需要相互适配。

一个简单为WebDriver代码

查看浏览器的版本 129.0版本,需要下载对应版本的driver,否则代码不能运行。

driver下载网址:

Chrome for Testing availability (googlechromelabs.github.io)

  1. 导入maven坐标
  2. <dependencies>
  3. <dependency>
  4. <groupId>org.seleniumhq.selenium</groupId>
  5. <artifactId>selenium-java</artifactId>
  6. <version>4.19.1</version>
  7. </dependency>
  8. </dependencies>

打开一个网站: 左上角会显示浏览器正在接收测试软件的控制。

HttpCilent

HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议。HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。

可以将httpclient封装成工具类在项目中使用。

HttpClient调用第三方服务-CSDN博客

爬取官网接口

需要拿到cookie,需要自动跳转到登录和注册页面。

首先在登录页面: 需要输入用户名和密码。 这个验证码是基于时间戳生成的,每一次的验证码都不一样。本质是一个图片,可以拿到这个图片存放到本地,在返回给前端。为了增加用户的体验感觉,使用百度的API识别验证码图片,提高用户的体验感。

打开页面是这样的,需要点击登录才能跳转到登录页面。获取到登录按钮,通过driver去点击登录。

/html/body/div[1]/article[1]/article/div[1]/div[1] 点击下面full path也可以,浏览器会自动点击登录按钮。

  1. WebElement element = wait.until(ExpectedConditions.visibilityOfElementLocated(By.xpath("/html/body/div[1]/article[1]/article/div[1]/div[1]")));
  2. element.click();

  1. //通过id 拿到用户名和密码的元素 通过sendkeys设置其中的值
  2. WebElement username = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("username")));
  3. WebElement password = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("password")));
  4. username.sendKeys("123456"));
  5. password.sendKeys("abc");

找到验证码:

点进去每一次刷新的验证码都不一样的。

  1. WebElement captchaElement = driver.findElement(By.id("captchaImg")); //扎到这个元素
  2. File screenshot = captchaElement.getScreenshotAs(OutputType.FILE); //进行截图
  3. File destinationFile = new File("captcha.png");
  4. try {
  5. FileHandler.copy(screenshot, destinationFile); //将截图拷贝到当前目录下面来
  6. } catch (IOException e) {
  7. throw new RuntimeException(e);
  8. }

调用百度云的接口进行识别。也可以自己训练本地的模型。

  1. AipOcr client = new AipOcr(APP_ID, API_KEY, SECRET_KEY);
  2. String path = destinationFile.getAbsolutePath();
  3. org.json.JSONObject res = client.basicGeneral(path, new HashMap<String, String>());
  4. String wordsResultJson = res.get("words_result").toString();
  5. JSONArray wordsResultArray = JSON.parseArray(wordsResultJson);
  6. JSONObject firstResult = wordsResultArray.getJSONObject(0);
  7. String words = firstResult.getString("words");
  8. String rescode = words.replaceAll(" ", ""); //去掉空格
  9. System.out.println(rescode);
  10. //将识别出来的验证码填充到框框中去
  11. WebElement code = wait.until(ExpectedConditions.visibilityOfElementLocated(By.id("captchaResponse")));
  12. code.sendKeys(rescode);

  1. //点击登录按钮
  2. WebElement loginButton = wait.until(ExpectedConditions.elementToBeClickable(By.xpath("//*[@id=\"casLoginForm\"]/p[5]/button")));
  3. loginButton.click();

运行代码发现成功了。

观察发现,虽然登录成功了,但是浏览器的地址并没有变化,如果浏览器的地址发生了变化需要进行刷新。

点击教务系统

发现网址变了,所以这边也需要修改对应的网址。

  1. for (String winHandle : driver.getWindowHandles()) {
  2. driver.switchTo().window(winHandle);
  3. }
  4. //因为需要等待五秒钟 五秒钟后可以直接刷新页面即可进来
  5. driver.navigate().refresh();

进入到了教育系统的页面

  1. Map<String, String> map = new HashMap<>();
  2. Set<Cookie> cookies = driver.manage().getCookies(); //拿到所有的cookie 存放到map中去
  3. for (Cookie cookie : cookies) {
  4. map.put(cookie.getName(), cookie.getValue());
  5. }
  6. StringBuffer sb = new StringBuffer();
  7. sb.append("JSESSIONID=" + map.get("JSESSIONID") + ";");
  8. sb.append("iPlanetDirectoryPro=" + map.get("iPlanetDirectoryPro") + ";");
  9. sb.append("route=" + map.get("route"));

到这第一步就算完成了,拿到了cookie。

HttpClient

导入HttpClient的包

  1. <dependency>
  2. <groupId>org.apache.httpcomponents</groupId>
  3. <artifactId>httpclient</artifactId>
  4. <version>4.5.13</version>
  5. </dependency>

请求的URL

  1. https://ensdp.njit.edu.cn:10443/http/webvpn3e1a11b7208e283ab07ade5d2913fc13d6f6fe09d2dc7372db2a51a14aa4167a/jwglxt/cjcx/cjcx_cxXsgrcj.html?doType=query&gnmkdm=N305005&enlink-vpn

携带了get和post的请求参数。 xnm 和xqm 确定了哪个学期。 还有一些查询参数 包括是否降序等等。

这是响应的数据,成绩相关的数据都在items中。

  1. public class Score {
  2. private Integer id;
  3. private String StudentName; //学生姓名
  4. private String StudentId; //学生学号
  5. private String CourseName; //课程名称
  6. private String type; //课程类型
  7. private Double credit; //课程学分
  8. private String score; //课程成绩 有的课程是优秀 不是分数
  9. }

发送post请求代码:

  1. public static String executePostRequest(String targetURL, Map<String, String> params, String cookie) {
  2. CloseableHttpClient httpClient = HttpClients.createDefault(); //创建httpCilent
  3. String responseBody = null; // 用于存储响应内容
  4. try {
  5. // 创建一个HttpPost实例,设置请求的URL
  6. HttpPost httpPost = new HttpPost(targetURL);
  7. // 设置请求头,模拟AJAX请求
  8. httpPost.setHeader("X-Requested-With", "XMLHttpRequest");
  9. httpPost.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36");
  10. httpPost.setHeader("Host", "ensdp.njit.edu.cn:10443");
  11. httpPost.setHeader("Origin", "https://ensdp.njit.edu.cn:10443");
  12. httpPost.setHeader("Referer", "https://ensdp.njit.edu.cn:10443/http/webvpn3e1a11b7208e283ab07ade5d2913fc13d6f6fe09d2dc7372db2a51a14aa4167a/jwglxt/kbcx/xskbcx_cxXskbcxIndex.html?gnmkdm=N2151&layout=default");
  13. httpPost.setHeader("Cookie", cookie);
  14. httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
  15. // 将参数转换为表单数据格式
  16. String postParams = params.entrySet().stream()
  17. .map(entry -> entry.getKey() + "=" + entry.getValue())
  18. .collect(Collectors.joining("&"));
  19. StringEntity entity = new StringEntity(postParams, StandardCharsets.UTF_8);
  20. httpPost.setEntity(entity);
  21. // 执行POST请求,获取HttpResponse对象
  22. HttpResponse response = httpClient.execute(httpPost);
  23. System.out.println(httpPost.getURI());
  24. // 获取响应的状态码并打印
  25. int statusCode = response.getStatusLine().getStatusCode();
  26. System.out.println("状态码: " + statusCode);
  27. // 获取响应实体
  28. HttpEntity responseEntity = response.getEntity();
  29. if (responseEntity != null) {
  30. // 将响应实体转换为字符串
  31. responseBody = EntityUtils.toString(responseEntity, StandardCharsets.UTF_8);
  32. }
  33. } catch (ClientProtocolException e) {
  34. // 处理客户端协议异常
  35. throw new RuntimeException(e);
  36. } catch (IOException e) {
  37. // 处理I/O异常
  38. throw new RuntimeException(e);
  39. } finally {
  40. // 确保关闭HttpClient对象,释放资源
  41. try {
  42. httpClient.close();
  43. } catch (IOException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. // System.out.println(responseBody);
  48. return responseBody;
  49. }

处理拿到的响应结果

responseBody是一个json格式的字符串,先转为json格式。拿到json中的items 数组。遍历items数组,每一个都是一个json对象。 这里使用了fastJson的库。

  1. String responseBody = executePostRequest(url, params,cookie);
  2. //打印了响应结果
  3. System.out.println("响应结果: " + responseBody);
  4. JSONObject jsonObject = JSON.parseObject(responseBody);
  5. JSONArray kbList = jsonObject.getJSONArray("items"); //拿到所有的成绩
  6. List<Score> scores = new ArrayList<>();
  7. for (Object o : kbList) {
  8. JSONObject jsonObject1 = (JSONObject) o;
  9. String StudentName = jsonObject1.getString("xm");
  10. String StudentId = jsonObject1.getString("xh");
  11. String courseName = jsonObject1.getString("kcmc");
  12. String grade = jsonObject1.getString("cj");
  13. String type = jsonObject1.getString("kcxzmc") + "课";
  14. double credit = Double.parseDouble(jsonObject1.getString("xf"));
  15. Score score = new Score(null, StudentName, StudentId, courseName, type, credit, grade);
  16. scores.add(score);
  17. }

代码运行结果


本文转载自: https://blog.csdn.net/ngczx/article/details/142686843
版权归原作者 全栈阿星 所有, 如有侵权,请联系我们删除。

“基于selenium和HttpClient框架爬取南京工程学院教务系统学生成绩”的评论:

还没有评论