由于博主的个人网站(:http://www.johnnyzen.cn/),每学期都需要更新呈现课程的静态信息,由于课程量多,而且手动爬取很冗杂,特别想自动化实现。这不,今天终于有点时间了,把之前写nodejs的爬虫的思路转移到前端js上,同时更新了抓取数据的算法,比起之前的来说,自然是更加灵活高效了。

声明:如读者需引用,必须在文章显著处声明或者与博主取得联系,以示尊重劳动成果,非常感谢 0.0

var Course = function(seletorForTds){
var tds = [];
var courseUnitCount = 0; //将dom对象数组转换为text文本数组
//TextnumFilter [以设置判断是否是课程的td格子的字符串长度作为特征判断值,如果没有达到此长度则会被删除 | 20]
var tdsToTextArray = function($tds,TextnumFilter){
if($tds == undefined)
throw new Error("$tds is not defined!"); if(TextnumFilter == undefined)
TextnumFilter = 20; var array = [];
for(var i = 0; i < $tds.length; i++){
if($tds[i].innerText.replace(/\s*/g,"").length > TextnumFilter){
array.push($tds[i].innerText.replace(/\s*/g,"").replace(/(<fontcolor=\"red\">(.[^font]*)<\/font>)*/g,""));
}
}
return array;
}; // (UTF-8)汉字转换为英文数字
var chineseToEnglishNumber = function(chiNum){
if(chiNum == undefined) throw new Error("$ don't load html!");
switch(chiNum){
case "零":return 0;break;
case "一":return 1;break;
case "二":return 2;break;
case "三":return 3;break;
case "四":return 4;break;
case "五":return 5;break;
case "六":return 6;break;
case "七":return 7;break;
case "八":return 8;break;
case "九":return 9;break;
}
} //从td中生成课程单元数组(但仍未被解析,属于课程单元的原始信息数组)
function generateCelltoCourseRawUnits(cell){
var cellItems = cell.innerText.split("\n");//以换行符为标志分割
// console.log('[generateCelltoCourseRawUnits] cellItems:', cellItems);
// console.log('[generateCelltoCourseRawUnits] cellItems[0]:', cellItems[0]);
var courses = [];
var previousStopFlag = false; //是否上一个数组元素也是停用标志元素:(调、(换、""等
var count = 0;//记录原始课程单元的元素的长度(4 or 6 等)
for(var i = 0, length = cellItems.length; i < length; i++){
// console.log('cellItems[' + i + '].indexOf("(换"): ', cellItems[i].indexOf("(换"));
// console.log('cellItems[' + i + '].indexOf("(调"): ', cellItems[i].indexOf("(调"));
// console.log('cellItems[' + i + ']: ', cellItems[i]); //假如当前元素是最后一个元素时
if(i == length-1){
if((cellItems[i].indexOf("(换") != -1) || (cellItems[i].indexOf("(调") != -1) || (cellItems[i] === "")){//如果当前元素为停用标志元素时
count++;
courses.push(cellItems.slice(i - count + 1, i));
// console.log('【1】cellItems.slice(' + i + ' - ' + count + ' + 1, ' + i + '):', cellItems.slice(i - count + 1, i));
}else if(previousStopFlag == false){//如果当前元素为非停用标志元素,且上一个元素非停用标志元素时
count++;
courses.push(cellItems.slice(i - count + 1, i + 1));
// console.log('【2】cellItems.slice(' + i + ' - ' + count + ' + 1, ' + i + '):', cellItems.slice(i - count + 1, i + 1));
}
} //如果当前元素是停用标志元素时
if( (cellItems[i].indexOf("(换") != -1) || (cellItems[i].indexOf("(调") != -1) || (cellItems[i] === "")){
if(previousStopFlag == false && (i != length-1)){//如果上一门课程未被填充且非最后一个元素时(即 上一个元素非停用标志元素且非最后一个元素时,push当前的course)
// console.log('push raw course:count:', count);
courses.push(cellItems.slice(i - count, i));
// console.log('【3】cellItems.slice(' + i + ' - ' + count + ', ' + i + '):', cellItems.slice(i - count, i)); } else {//上一个元素为停用标志元素时 } count = 0;
// console.log("count " + count + " 【" + i + "】" + cellItems[i] + ' test 3');
previousStopFlag = true;//表示已经将上一门课程是停用标志元素 } else {//如果当前元素不是停用标志元素
if( (previousStopFlag == true) || (i == 0)) { //如果上一个元素是停用标志元素或者当前元素属于第一个元素,则说明当前元素已经属于一门新的课程信息的单元对象的课程名了,需要创建一个新的课程单元数组 } else { //如果上一个元素不是停用标志元素且非首元素,则说明当前元素已经属于正在填充的课程单元 }
// if(i != length-1){
count++;
// console.log("count " + count + " 【" + i + "】" + cellItems[i] + ' test 1');
previousStopFlag = false;
// }
}
}
// console.log('courses:', courses);
return courses;
} //根据原始的课程单元生成课程对象
var generateCourses = function(CourseRawUnits,courses){
for(var i = 0,CourseUnitSize = CourseRawUnits.length; i < CourseUnitSize; i++){
switch(CourseRawUnits[i].length) {//根据课程单元的元素长度解析成对应课程对象
case 4:
case 6:{
var course = {}; course.name = CourseRawUnits[i][0];
course.week_index =chineseToEnglishNumber( CourseRawUnits[i][1].charAt( CourseRawUnits[i][1].search(/周[一二三四五六七]/gi) + 1 )); try {
var patCourse_index = new RegExp("第\\d*[,\\d*]*节","gi"); // console.log('test CourseRawUnits[i][1]:', CourseRawUnits[i][1]);
course.course_index = patCourse_index.exec(CourseRawUnits[i][1])[0].replace("第","").replace("节","").split(",").map(function(ele,index,array){
return parseInt(ele);
})
// console.log('course.course_index:', course.course_index );
} catch(error){
console.log('[generateCourses] error.message:', error.message); } var patWeeks = new RegExp("第\\d*[-]*[\\d*]*周","gi");
// var course_indexArray = pat.exec(CourseRawUnits[i][1])[0].split("-");
var course_Weeks = patWeeks.exec(CourseRawUnits[i][1])[0].replace("第","").replace("周","").split("-").map(function(ele,index,array){
return parseInt(ele);
}) // console.log('test course_Weeks:', course_Weeks); course.week_start = course_Weeks[0];
course.week_end = course_Weeks[1]; course.teacher = CourseRawUnits[i][2];
course.location = CourseRawUnits[i][3]; courses.push(course);
break;
}
case 0:
break;
}
}
return courses;
} //清除无关dom节点
var ArraysClearEmptyItem = function(array,condition){
if(tds == undefined)
throw new Error("tds is not defined!");
// console.log('ArrayClearEmptyItem array', array); var newArray = [];
for(var i = 0; i < array.length; i++){
// console.log('[ArrayClearEmptyItem] array[i].innerText:', array[i].innerText);
if(array[i].innerText.length > 20 && array[i].innerText != "&nbsp;"){
newArray.push(array[i]);
// console.log('push:', array[i]);
}
}
return newArray;
}; // [ArrayClearEmptyItem 清除数组内为空字串""的元素]
var ArrayClearEmptyItem = function(array,condition){
if(tds == undefined) throw new Error("tds is not defined!"); var newArray = [];
for(var i = 0;i < array.length;i++){
if(array[i].length > 1){
newArray.push(array[i]);
// console.log('push:',array[i]);
}
}
return newArray;
} var tdsItemsToCourses = function($tds){ //$tds.length
if($tds == undefined)
throw new Error("$tds is not defined!"); $tds = ArraysClearEmptyItem($tds);//清除数组内空字串""的元素 var courses = [];
for(var j = 0; j < $tds.length; j++){
courses = generateCourses(generateCelltoCourseRawUnits($tds[j]), courses);
}
return courses;
}; this.load = function(){
tds = document.querySelectorAll(seletorForTds); // console.log('tds:', tds);
tdsToTextArray(tds, 20);
var courses = tdsItemsToCourses(tds); // console.log('courses: ', courses);
// window.courses = courses;
// console.log("课表课程解析:\n",JSON.stringify(courses)); return courses;
}
} var Student = function(seletorOption){
var that = this;
that.load = function(){
return {
sno : document.querySelectorAll(seletorOption.sno)[0].innerText.trim().replace(/学号:/gi, ""),
sname : document.querySelectorAll(seletorOption.sname)[0].innerText.trim().replace(/姓名:/gi, ""),
college : document.querySelectorAll(seletorOption.college)[0].innerText.trim().replace(/学院:/gi, ""),
profession : document.querySelectorAll(seletorOption.profession)[0].innerText.trim().replace(/专业:/gi, ""),
clazz : document.querySelectorAll(seletorOption.clazz)[0].innerText.trim().replace(/行政班:/gi, ""),
courses: (new Course(seletorOption.courseTable)).load()
}
};
that.stringify = function(){
return JSON.stringify(that.load());
}
} //demo
var seletorOption = {
sno:"#Label5",
sname:"#Label6",
college:"#Label7",
profession:"#Label8",
clazz:"#Label9",
courseTable:"#Table1 td"
};
var student = (new Student(seletorOption));

JavaScript之从浏览器一键获取教务处个人课程信息【插件】的更多相关文章

  1. js 如何在浏览器中获取当前位置的经纬度

    这个有一定的误差哈,具体的误差是多少,有兴趣的朋友可以去测试下 直接上代码 index.html页面代码: <html> <head lang="en"> ...

  2. 6、JavaScript进阶篇③——浏览器对象、Dom对象

    一.浏览器对象 1. window对象 window对象是BOM的核心,window对象指当前的浏览器窗口. window对象方法: 注意:在JavaScript基础篇中,已讲解了部分属性,windo ...

  3. 用Javascript编写Chrome浏览器插件

    原文:http://homepage.yesky.com/62/11206062.shtml 用Javascript编写Chrome浏览器插件 2010-04-12 07:30 来源:天极网软件频道 ...

  4. Javascript进阶篇——浏览器对象—Location、Navigator、userAgent、screen对象

    Location对象location用于获取或设置窗体的URL,并且可以用于解析URL.语法: location.[属性|方法] location对象属性图示: location 对象属性: loca ...

  5. 通过JavaScript判断当前浏览器版本

    从别人处拷贝,只用于自己学习之用.参考源自:http://www.cnblogs.com/leadzen/archive/2008/09/06/1285764.html JavaScript是前端开发 ...

  6. 第一百一十一节,JavaScript,BOM浏览器对象模型

    JavaScript,BOM浏览器对象模型 学习要点: 1.window对象 2.location对象 3.history对象 BOM也叫浏览器对象模型,它提供了很多对象,用于访问浏览器的功能.BOM ...

  7. 微信跳转,手机WAP浏览器一键超级跳转微信指定页面

    微信跳转,手机WAP浏览器一键超级跳转微信指定页面 这篇文章主要介绍了如何在手机浏览器wap网页中点击链接跳转到微信界面,需要的朋友可以参考下 先说第一种,最简单的唤起微信协议,weixin://主流 ...

  8. 原生JavaScript支持6种方式获取元素

    一.原生JavaScript支持6种方式获取元素 document.getElementById('id'); document.getElementsByName('name'); document ...

  9. JavaScript和微信小程序获取IP地址的方法

    最近公司新加了一个需求,根据用户登录的IP地址判断是否重复登录,重复登录就进行逼退,那么怎么获取到浏览器的IP地址呢?最后发现搜狐提供了一个JS接口,可以通过它获取到客户端的IP. 接口地址如下: h ...

随机推荐

  1. 【转】fscanf 跳过空格,读取一行

    fscanf(fp, "%s", sLineWord); 以上语句,在读取一行数据时,如何遇到该行数据有空格,那么读到空格处就停止,不再继续向下读. 若想遇到空格继续读取,读取完整 ...

  2. mysql 常用命令导入导出修改root密码

    MySQL 忘记口令的解决办法如果 MySQL 正在运行,首先杀之: killall -TERM mysqld. 启动 MySQL :mysql --skip-grant-tables & / ...

  3. BZOJ3718[PA2014]Parking——树状数组

    题目描述 你的老板命令你将停车场里的车移动成他想要的样子.停车场是一个长条矩形,宽度为w.我们以其左下角顶点为原点,坐标轴平行于矩形的边,建立直角坐标系.停车场很长,我们可以认为它一直向右边伸展到无穷 ...

  4. BZOJ2152[国家集训队]聪聪可可——点分治

    题目描述 聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃.两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已 ...

  5. day6 字符串

    重复输出字符串 # * 重复输出字符串 print("hello"*2) 字符串切片 # 字符串也拥有索引,和列表切片操作类似 print("helloworld&quo ...

  6. MT【220】三次方程必有实根

    设$f(x)=x^2+ax+b,g(x)=x^2+cx+d$,如果$f(g(x))=g(f(x))$没有实根,求证:$b\ne d$ 分析:$f(g(x))-g(f(x))=2(c-a)x^3+\cd ...

  7. 自学Linux Shell18.3-sed实用工具

    点击返回 自学Linux命令行与Shell脚本之路 18.3-sed实用工具 1. 加倍行间距 命令格式: .......

  8. 【BZOJ2875】【NOI2012】随机数生成器(矩阵快速幂)

    [BZOJ2875]随机数生成器(矩阵快速幂) 题面 Description 栋栋最近迷上了随机算法,而随机数是生成随机算法的基础.栋栋准备使用线性同余法(Linear Congruential Me ...

  9. USACO 好题汇总

    背景 这里主要是用来针对USACO上的题目的二次汇总,因为我在刷题的过程中,有的题目我是可以很快想到解决方案的,对于这种题目,就没有必要深究了.但是有一些题目对于我来说还是有一些挑战的,可能用朴素的算 ...

  10. Codeforces Round #510 (Div. 2)(A)

    传送门:Problem A https://www.cnblogs.com/violet-acmer/p/9682082.html 题意: 公园里有n个沙滩,a[i]表示第i个沙滩初始人数,现有m个人 ...