第二次结对作业:班级成绩表

作业要求 https://edu.cnblogs.com/campus/fzzcxy/2018SE2/homework/11248
作业目标 通过联网直接爬取数据,用cookie进行模拟登陆
作业源代码 作业仓库
队员1 211806413王奕峻
队员2 211806391李润泽

伙伴评价

李润泽:是一个非常认真的伙伴,在我每次编码遇到难点是都会积极的帮我寻找解决办法以及提供思路。

王奕峻:在这次的结对作业中,可以感受到奕峻同学是一个可靠的搭档,在完成任务的过程中他指正了我的一些不足。

结对过程

由于国庆假期的原因我溜回家了,并且国庆期间我每天都有活动(各种亲戚朋友聚餐),所以我们结对编程编程的时间被我压得零零碎碎(我的锅)。所以我们这次的编程时间大约用了快6个小时。

编码过程

本次作业的爬取数据跟上次有些区别。在此次作业中我们不在将一个本地页面进行解析而是通过联网来直接进行解析网页,这样就会遇到个问题!为了拿到我们的经验值这就需要我们去登录我们的账号,这样子我们才能进入我们用户的主界面,否则就是云班课首页。所以我们需要用cookie进行模拟登陆。以下是Chrome获取cookie的方式。

之后就是进行配置文件的设置

Properties pps = new Properties();
	pps.load(new FileInputStream("src\config.properties"));
	String url = pps.getProperty("url");//获取云班的URL
	String cookie = pps.getProperty("cookie");//获取cookie
	List list = new ArrayList();
	//解析云班课活动主页
	Document document =Jsoup.connect(url).header("Cookie", cookie).timeout(30000).maxBodySize(0).get();//通过cookie进行模拟登陆

由于本次爬取我们只需要课堂完成部分所以我们需要获取课堂完成部分的url。

String[] arrUrl = new String[99];//定义一个存储各个课堂完成部分url的数组
Elements elements = document.getElementsByClass("interaction-row");
	for (i=0;i<elements.size();i++) {
		if (elements.get(i).toString().contains("课堂完成")) {
			arrUrl[k]=(String)elements.get(i).attr("data-url");
			k++;//课堂完成部分总数
		}
	}

当然获取每个课堂完成部分url之后我们也需要通过上述方法进行连接。

Document document2=Jsoup.connect(arrUrl[i]).header("Cookie", cookie).timeout(30000).maxBodySize(0).get();//解析课堂完成部分页面

之后的操作跟之前的方法大同小异,不过在获取经验值的时候需要考虑是否提交,我直接用try catch直接进行暴力获取,不让他报错并将每次的任务经验值默认为0,若获取不到经验值就直接为0。

try {
	if(elements2.get(m).child(3).child(1).text().replaceAll("[最终得分:]", "")!=null) {
		exp=Double.parseDouble(elements2.get(m).child(3).child(1).text().replaceAll("[最终得分:]", ""));
} catch (Exception e) {
	// TODO: handle exception
	}

之后就是进行数据的存储,创建自定义对象Student之后用集合进行存储这样在每次作业的存储中就能进行contains判断是否有重复对象这需要重写Student的equals方法。

public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (obj == null)
		return false;
	if (getClass() != obj.getClass())
		return false;
		Student other = (Student) obj;
	if (num == null) {
		if (other.num != null)
		return false;
	} else if (!num.equals(other.num))
		return false;
	return true;
	}

只需要学号就可以了,这样就能判断是否有重复学号若有则视为已有对象将对象的经验值进行更新,若没有则创建对象并添加到集合中。

Student s=new Student(name, num, exp);//临时对象用于判断是否存在
	if (list.contains(s)) {
		for (int a = 0; a < list.size(); a++) {
			Student s1 = (Student) list.get(a);
			if (s1.getName().equals(name)) {
			      s1.setExp(s1.getExp()+exp);
			}
		}
	}
	else {
	      list.add(new Student(name, num, exp));
	}

但是!!!

不知道为什么有些作业存在“幽灵成员”,就是在有些作业中成员人数会变动,除去助教范围在69-72之间变动。我猜应该是重修的同学中途退出云班了。这样直接在主页中获取的成员总数作为每次遍历课堂完成部分的限制条件的话就会出现溢出的现象。所以要以每个页面中的homework-item这个class的数目为准。

最后就是将集合进行降序排序,以文本输出最高最低的经验以及平均经验。

list.sort(new Comparator<Student>() {
	public int compare(Student o1, Student o2) {
	return (int) (o2.getExp() - o1.getExp());
	}
		});
for (i = 0; i < list.size(); i++) {
      Student student = (Student) list.get(i);
      avg += student.getExp();
      }
avg = avg / list.size();
String avgString = String.format("%.1f", avg);
Student stumax = (Student) list.get(0);
Student stumin = (Student) list.get(list.size() - 1);
File file = new File("Score.txt");
PrintStream pts = new PrintStream(file);
pts.println("最高经验值:" + stumax.getExp() + ",最低经验值:" + stumin.getExp() + ",平均经验值:" + avgString);
for (i = 0; i < list.size(); i++) {
	Student student = (Student) list.get(i);
	pts.println(student.getName() + " " + student.getNum() + " " + student.getExp());
	}
pts.close();

小结

在本次作业中感觉还是没有能使用更简洁的功能。并且在编码中经常修修改改,下手前不去仔细思考一些存在的问题,这里消耗的大多时间。好在是结对编程,在编码中会有小伙伴的提醒。这让我反应更加迅速,避免在错误中消耗大量时间。

原文地址:https://www.cnblogs.com/211806413wangyijun/p/13766014.html