爬取学校超星网上未完成作业或考试,并输出至qq邮箱

爬取学校超星网上未完成作业或考试,并输出至qq邮箱

项目结构采用我之前编写的爬虫模板
爬虫模板.

相关接口

因为完成代码和写这篇笔记隔了好几天的,懒得截图接口信息了,这里就贴上我之前爬取的笔记,可以自己去抓取下练练手

courseid,classid,cpi等参数为 id 类,是不变的,且后续网站提供的链接并无此类参数,可以储存起来,
而每个链接都需要enc,而enc随机生成,每个链接都不一样,所以不能采用一步到位爬取,得依次爬取解析html取出链接访问

/**
 * 姓名,学号,电话接口: 
 *  这里是会有参数的,但是我当时忘了贴
 * 	@返回:html
 * http://passport2.chaoxing.com/mooc/accountManage	
 * 
 * 课程数据接口:
 * 这里是会有参数的,但是我当时忘了贴
 *  @返回:html
 * http://mooc1-1.chaoxing.com/visit/courselistdata
 * 
 * 课程首页接口:
 *  @参数:可来自课程数据接口
 * courseid,courseid,cpi为
 * 	@返回:html   
 * https://mooc2-ans.chaoxing.com/mycourse/stu?courseid=???&classId=???&cpi=???&enc=cda787016ce2c1f162fe6230b02bf948&t=1630417924301&pageHeader=9
 * 
 * 课程作业接口:
 *  @参数:来自课程首页
 *  @返回:html
 * https://mooc1.chaoxing.com/mooc2/work/list?courseId=?&classId=?&cpi=?&enc=27719c62b0263f5249aa52edea81c125&
 * 
 * 课程考试接口:
 *  @参数:来自课程首页
 *  @返回html
 * https://mooc1.chaoxing.com/mooc2/exam/exam-list?enc=a13c03b8366c587872c31e0a5d16eac6&openc=5a474025b333b5b147076b1eb3c38ab3&courseid=???&clazzid=???031&cpi=???&ut=s
 * 
 * 课程任务接口:
 *  @参数:来自课程首页
 *  @返回:json
 * https://mobilelearn.chaoxing.com/v2/apis/active/student/activelist?fid=1971&courseId=???&classId=???
 *

思路

获取课程信息->构造首页链接->访问考试,作业接口->解析出未完成,并添加到json,

得到接口后,就开始分析.因为访问课程考试,作业信息时,有enc参数,此参数不固定,为服务器随机生成,所以不能直接访问,且课程首页提供的链接不包含课程的courseid,classid,cpi,
需要先到课程首页获取考试,作业链接,并添加courseid,classid,cpi,访问获得考试,课程信息
得到信息后解析,输出

登录

登录没什么说的,主要看地址,参数
地址抓包来的
参数 分析
分析出那些为通用参数(人人都一样)
那些为个性化参数(都有,但没有不一样)
在分析下加密
完成

	@Override
	public boolean login() {
		boolean result = false;
		CloseableHttpClient httpclient = HttpClients.createDefault();
		HttpClientContext httpClientContext = HttpClientContext.create();
		HttpPost post = new HttpPost("http://passport2.chaoxing.com/fanyalogin");
		//将密码用base64方式
		String upwbase64password = base64(password);
		List<NameValuePair> paramslist = new ArrayList<NameValuePair>();
		paramslist.add(new BasicNameValuePair("fid", "1971"));//常量
		paramslist.add(new BasicNameValuePair("uname", uname));
		paramslist.add(new BasicNameValuePair("password", upwbase64password));
		paramslist.add(new BasicNameValuePair("refer", "http://i.mooc.chaoxing.com"));//常量
		paramslist.add(new BasicNameValuePair("t", "true"));//常量
		try {
			UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(paramslist, "UTF-8");
			post.setEntity(urlEncodedFormEntity);
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		CloseableHttpResponse response;
		try {
			response = httpclient.execute(post, httpClientContext);
			if (response.getStatusLine().getStatusCode() == 200) {
			//将服务器返回的cookie放在cookieStore中,以便下次使用
				cookieStore = httpClientContext.getCookieStore();
				result = true;
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

爬取课程信息

courseid,classid,cpi等参数为 id 类,描述课程id,学生id,是不变的,且后续网站提供的链接并无此类参数(js动态链接),可以储存起来,
这个方法爬取用户首页并获取课程信息,并储存至全局变量courselist中

public void getcourse() {
		courselist = new ArrayList<schoolclass>();
		HashMap<String, String> params = new HashMap<String, String>();
		params.put("courseType", "1");
		params.put("courseFolderId", "0");
		params.put("courseFolderSize", "0");
		HttpResponse response = post("http://mooc1-1.chaoxing.com/visit/courselistdata", params);
		Document document = null;
		try {
			document = Jsoup.parse(EntityUtils.toString(response.getEntity()));
		} catch (ParseException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		Elements elements = document.getElementsByAttributeValue("class", "course clearfix");
		elements.forEach(element -> {
			String courseid = element.attr("courseId");
			String clazzId = element.attr("clazzId");
			String cpi = element.attr("personId");
			String name = element.child(1).child(0).child(0).child(0).text();
			courselist.add(new schoolclass(name, courseid, clazzId, cpi));
		});
	}

根据课程信息构造链接爬取作业和考试信息

此方法为获取单门课程的信息,还封装了一个遍历所有课程的方法,见全代码

public JSONObject getUncompleteHomeworkAndexame(schoolclass sc) throws ParseException, IOException {
		JSONObject jclass = new JSONObject();
		JSONArray ja = new JSONArray();
		String url = "https://mooc2-ans.chaoxing.com/mycourse/stu?courseid=" + sc.getCourseid() + "&cpi=" + sc.getCpi()
				+ "&clazzid=" + sc.getClassid() + "&pageHeader=8";
		HttpResponse httpResponse = get(url, null);
		Document document = null;
		document = Jsoup.parse(EntityUtils.toString(httpResponse.getEntity()));
		Elements homework = document.getElementsByAttributeValue("title", "作业");
		Elements exame = document.getElementsByAttributeValue("title", "考试");
		String homeworkurl = homework.attr("data-url");
		String exameurl = exame.attr("data-url") + "&courseid=" + sc.getCourseid() + "&cpi=" + sc.getCpi() + "&clazzid="
				+ sc.getClassid();
		HttpResponse homeworkresponse = get(homeworkurl, null);
		Document homeworkdocument = Jsoup.parse(EntityUtils.toString(homeworkresponse.getEntity()));
		Elements homeworks = homeworkdocument.getElementsByTag("li");
		homeworks.forEach(li -> {
			if (li.getElementsByClass("status").text().equals("未交")) {
				String hwname = li.getElementsByClass("overHidden2 fl").text();
				Elements time = li.getElementsByClass("time notOver");
				if(!time.isEmpty()) {
					String timestr=time.text();
					JSONObject jo = new JSONObject();
			        jo.put("名称", hwname);
			        jo.put("类型","作业");
			        jo.put("时间",timestr);
			        ja.add(jo);
				}
			}
		});
		HttpResponse exameresponse = get(exameurl, null);
		Document examedocument = Jsoup.parse(EntityUtils.toString(exameresponse.getEntity()));
		Elements exames = examedocument.getElementsByTag("li");
		exames.forEach(li -> {
			if (li.getElementsByClass("status").text().equals("未完成")) {
				String hwname = li.getElementsByClass("overHidden2 fl").text();
				Elements time = li.getElementsByClass("time notOver");
				if(!time.isEmpty()) {
					String timestr=time.text();
					JSONObject jo = new JSONObject();
			        jo.put("名称", hwname);
			        jo.put("类型","考试");
			        jo.put("时间",timestr);
			        ja.add(jo);
				}
			}
		});
		if(!ja.isEmpty()) {
			jclass.put("name",sc.getName());
			jclass.put("uncompleted", ja);
		}
		return jclass;
	}
	

全代码

public class caoxing extends mypachongimpl {
	String password;//密码 ,且密码采用base64加密
	String uname;//账号
	String email;//要接受的邮箱
	//shcoolclass封装了courseid,classid,cpi等参数,至于为啥有俩list,我也忘了
	List<schoolclass> classlist = null; 
	List<schoolclass> courselist = null;
	//构造器
	public caoxing(String uname, String password,String email) {
		this.password = password;
		this.uname = uname;
		this.email = email;
	}
	public caoxing() {
	}
	//相当于主函数 ,解析其他方法构造的json信息并发送.在使用时,直接调用这个方法
	public void domain() {
			JSONArray json=null;
			try {
				json = getUncomplete();//这个方法返回所有未完成项目的json,主要的爬虫代码就在这个方法中
			} catch (ParseException e1) {
				e1.printStackTrace();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
			if(!json.isEmpty()) {
				Iterator<JSONObject> iter = json.iterator();
				String str="";
				while(iter.hasNext()) {
					JSONObject next = iter.next();
					String classname = (String) next.get("name");
					JSONArray uncompletedlist = (JSONArray) next.get("uncompleted");
					Iterator<JSONObject> listiter = uncompletedlist.iterator();
					String strlist="";
					while(listiter.hasNext()) {
						JSONObject next2 = listiter.next();
						String taskname = (String) next2.get("名称");
						String type = (String) next2.get("类型");
						String time = (String) next2.get("时间");
						strlist="<br>您的: "+taskname+"存在未完成:"+type+" "+time;
					}
					str+="您的 "+classname+" "+"存在未完成作业或考试,名单如下:"+strlist+"<br>";
				}
				mail.sendmail(email,str);//发送邮件,我直接封装的mail模块,csdn上一代堆,拿过来封装成一个类,哪里需要cv哪里
			}
	}
	/**
	 * ��ȡ����δ��ɵ���ҵ�Ϳ���(����ʱ��)
	 * @return 
	 * @throws ParseException
	 * @throws IOException
	 */
	public JSONArray getUncomplete() throws ParseException, IOException {
		if(courselist==null) getcourse();
		Iterator<schoolclass> iter =courselist.iterator();
		JSONArray ja = new JSONArray();
		while (iter.hasNext()) {
			schoolclass next = iter.next();
			JSONObject jo = getUncompleteHomeworkAndexame(next);
			if(!jo.isEmpty()) {
				ja.add(jo);
			}
		}
		return ja;
	}
	/**
	 * ��ȡ���ſγ�δ��ɵ���ҵ�Ϳ���(����ʱ��)
	 * @param sc ��Ҫ��ѯ��school����
	 * @return ����JSONObject
	 * @throws ParseException
	 * @throws IOException
	 */
	public JSONObject getUncompleteHomeworkAndexame(schoolclass sc) throws ParseException, IOException {
		JSONObject jclass = new JSONObject();
		JSONArray ja = new JSONArray();
		String url = "https://mooc2-ans.chaoxing.com/mycourse/stu?courseid=" + sc.getCourseid() + "&cpi=" + sc.getCpi()
				+ "&clazzid=" + sc.getClassid() + "&pageHeader=8";
		HttpResponse httpResponse = get(url, null);
		Document document = null;
		document = Jsoup.parse(EntityUtils.toString(httpResponse.getEntity()));
		Elements homework = document.getElementsByAttributeValue("title", "作业");
		Elements exame = document.getElementsByAttributeValue("title", "考试");
		String homeworkurl = homework.attr("data-url");
		String exameurl = exame.attr("data-url") + "&courseid=" + sc.getCourseid() + "&cpi=" + sc.getCpi() + "&clazzid="
				+ sc.getClassid();
		HttpResponse homeworkresponse = get(homeworkurl, null);
		Document homeworkdocument = Jsoup.parse(EntityUtils.toString(homeworkresponse.getEntity()));
		Elements homeworks = homeworkdocument.getElementsByTag("li");
		homeworks.forEach(li -> {
			if (li.getElementsByClass("status").text().equals("未交")) {
				String hwname = li.getElementsByClass("overHidden2 fl").text();
				Elements time = li.getElementsByClass("time notOver");
				if(!time.isEmpty()) {
					String timestr=time.text();
					JSONObject jo = new JSONObject();
			        jo.put("名称", hwname);
			        jo.put("类型","作业");
			        jo.put("时间",timestr);
			        ja.add(jo);
				}
			}
		});
		HttpResponse exameresponse = get(exameurl, null);
		Document examedocument = Jsoup.parse(EntityUtils.toString(exameresponse.getEntity()));
		Elements exames = examedocument.getElementsByTag("li");
		exames.forEach(li -> {
			if (li.getElementsByClass("status").text().equals("未完成")) {
				String hwname = li.getElementsByClass("overHidden2 fl").text();
				Elements time = li.getElementsByClass("time notOver");
				if(!time.isEmpty()) {
					String timestr=time.text();
					JSONObject jo = new JSONObject();
			        jo.put("名称", hwname);
			        jo.put("类型","考试");
			        jo.put("时间",timestr);
			        ja.add(jo);
				}
			}
		});
		if(!ja.isEmpty()) {
			jclass.put("name",sc.getName());
			jclass.put("uncompleted", ja);
		}
		return jclass;
	}

	/**
	 * ��¼֮���ȡ�γ���Ϣ,����ֵ������ij�Ա����
	 */
	public void getcourse() {
		courselist = new ArrayList<schoolclass>();
		HashMap<String, String> params = new HashMap<String, String>();
		params.put("courseType", "1");
		params.put("courseFolderId", "0");
		params.put("courseFolderSize", "0");
		HttpResponse response = post("http://mooc1-1.chaoxing.com/visit/courselistdata", params);
		Document document = null;
		try {
			document = Jsoup.parse(EntityUtils.toString(response.getEntity()));
		} catch (ParseException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		Elements elements = document.getElementsByAttributeValue("class", "course clearfix");
		elements.forEach(element -> {
			String courseid = element.attr("courseId");
			String clazzId = element.attr("clazzId");
			String cpi = element.attr("personId");
			String name = element.child(1).child(0).child(0).child(0).text();
			courselist.add(new schoolclass(name, courseid, clazzId, cpi));
		});
	}

	/**
	 * ����������get,postʵ��,��Ϊ,get,post����ô˷�����ʼ��cookieStore
	 */
	@Override
	public boolean login() {
		boolean result = false;
		CloseableHttpClient httpclient = HttpClients.createDefault();
		HttpClientContext httpClientContext = HttpClientContext.create();
		HttpPost post = new HttpPost("http://passport2.chaoxing.com/fanyalogin");
		String upwbase64password = base64(password);
		List<NameValuePair> paramslist = new ArrayList<NameValuePair>();
		paramslist.add(new BasicNameValuePair("fid", "1971"));
		paramslist.add(new BasicNameValuePair("uname", uname));
		paramslist.add(new BasicNameValuePair("password", upwbase64password));
		paramslist.add(new BasicNameValuePair("refer", "http://i.mooc.chaoxing.com"));
		paramslist.add(new BasicNameValuePair("t", "true"));
		try {
			UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(paramslist, "UTF-8");
			post.setEntity(urlEncodedFormEntity);
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		}
		CloseableHttpResponse response;
		try {
			response = httpclient.execute(post, httpClientContext);
			if (response.getStatusLine().getStatusCode() == 200) {
				cookieStore = httpClientContext.getCookieStore();
				result = true;
			}

		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return result;
	}

	/**
	 * 
	 * @param str Ҫ���ܵ�str
	 * @return ���ܺ��str
	 */
	public static String base64(String str) {
		String result = null;
		// ��Ϊ�ջ�null��ֱ�ӷ���null
		if (str.equals("") || str == null) {
			return null;
		}
		byte[] bytes = str.getBytes();
		result = Base64.getEncoder().encodeToString(bytes);
		return result;
	}
}
<think>好的,我现在需要解决用户遇到的AttributeError: module '_winapi' has no attribute 'SYNCHRONIZE'错误。这个问题出现在运行loky代码时,用户提到使用了Python在Windows环境下。首先,我应该回忆一下这个错误可能的原因以及常见的解决方法。 根据引用[1]、[3]、[4],这个错误通常与Python环境依赖库的版本不兼容有关,特别是在Windows系统上使用发处理库如joblibloky时。用户可能在Anaconda环境中运行,所以需要检查Python版本和相关库的兼容性。 首先,Python的_winapi模块在较新的版本中可能有所变化。SYNCHRONIZE属性可能在旧版Python中不存在,者某些库在调用时错误地引用了这个属性。比如,在Python 3.7及以下版本中,可能没有这个属性,者某些库如joblib/loky在特定版本中存在兼容性问题。 解决方案可能包括升级Python到更高版本,比如3.8以上,因为这些版本可能已经包含了必要的_winapi模块属性。另外,检查joblibloky的版本,确保它们与当前Python版本兼容。用户可能安装了旧版本的joblib,导致引用了不存在的属性。 此外,环境问题也是一个可能因素。如果用户使用虚拟环境,可能存在依赖冲突。重新创建虚拟环境重新安装依赖可能有效。引用[4]提到,不同环境电脑之间可能存在库版本不一致的问题,所以确保环境的一致性很重要。 还有一种可能是第三方库如ctypes的使用问题,如引用[5]中的代码涉及CreateThread函数,可能与Windows API的调用方式有关,但不确定是否与此错误直接相关,但需要确认是否有代码错误地调用了_winapi模块。 综上所述,解决步骤可能包括: 1. 升级Python到3.8+。 2. 更新joblib和loky库到最新版本。 3. 检查环境配置,必要时重建虚拟环境。 4. 验证代码中是否有直接调用_winapi的错误用法。 需要确保用户按照这些步骤操作,验证是否解决了问题。同时,生成相关问题,帮助用户深入理解类似错误的解决方法。</think>### 解决方案:AttributeError: module '_winapi' has no attribute 'SYNCHRONIZE' 此错误通常由Python环境版本与依赖库不兼容引起,尤其是在Windows系统中使用发处理库(如`joblib``loky`)时。以下是逐步解决方案: --- #### 1. **确认Python版本** `_winapi.SYNCHRONIZE`属性在Python 3.8及以上版本中才被完整支持[^1]。 **操作步骤:** - 打开命令行,输入`python --version`查看当前Python版本。 - 若版本低于**3.8**,需升级Python: - 从[Python官网](https://www.python.org/downloads/windows/)下载最新版本安装包。 - 安装时勾选“Add Python to PATH”覆盖旧版本。 --- #### 2. **更新依赖库** 旧版本的`joblib``loky`可能与Python 3.8+不兼容。 **操作步骤:** - 升级`joblib`和`loky`: ```bash pip install --upgrade joblib loky ``` - 若使用Anaconda,尝试: ```bash conda update joblib loky ``` --- #### 3. **重建虚拟环境(可选)** 若环境存在依赖冲突,建议重建虚拟环境[^4]。 **操作步骤:** ```bash # 删除旧环境 conda remove --name your_env_name --all # 创建新环境激活 conda create -n new_env_name python=3.10 conda activate new_env_name # 重新安装依赖 pip install joblib loky ``` --- #### 4. **验证代码兼容性** 检查代码中是否有直接调用`_winapi`模块的行为(如多进程相关操作),确保语法符合Python 3.8+规范[^3]。 --- ### 总结 通过升级Python到3.8+、更新依赖库、重建环境,可解决90%以上的此类错误。若问题依旧,需检查第三方库是否调用了不兼容的底层API。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值