Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ratings from RateMyProfessors.com #86

Merged
merged 3 commits into from
Aug 27, 2011
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 27 additions & 1 deletion antplanner.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from google.appengine.api import memcache
from google.appengine.api import users

import logging

urls = (
'/', 'index',
'/search', 'search',
Expand All @@ -19,7 +21,8 @@
'/admin', 'admin',
'/admin/flush-cache', 'adminFlushCache',
'/admin/latest-web-soc', 'latestWebSoc',
'/admin/delete-old-schedules', 'deleteOldSchedules'
'/admin/delete-old-schedules', 'deleteOldSchedules',
'/prof', 'getProf'
)

render = web.template.render('templates/')
Expand Down Expand Up @@ -107,6 +110,29 @@ class loadSchedule():
def GET(self):
return schedule.load_schedule(web.input().username)

class getProf():
def GET(self):
p = web.input()
#logging.debug(p)
#data = memcache.get("PROF")
if p is None or p.name is None:
return get_rmp_error('Empty Request','The professor must have a last name in order to find ratings.')
#if data is None:
try:
q = urllib.quote_plus(p.name[0])
#logging.debug('Query param: ' + q)
raw_page = urlfetch.fetch("http://www.ratemyprofessors.com/SelectTeacher.jsp?the_dept=All&sid=1074&orderby=TLName&letter=" + q,
method=urlfetch.GET,
deadline=10)
data = scraper.strip_professors(raw_page.content, unicode(p.name))
#memcache.add("PROF", data, 60 * 60)
except urlfetch.DownloadError:
data = get_rmp_error('urlfetch.DownloadError','RateMyProfessors.com request exceeded 10 seconds')
except urlfetch.Error:
data = get_rmp_error('urlfetch.Error','RateMyProfessors.com is not available at the moment')

return data

if __name__ == "__main__":
app = web.application(urls, globals())
app.cgirun()
6 changes: 3 additions & 3 deletions app.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
application: antplanner
version: release-0-9-8-1
application: antplanner-fork
version: release-0-9-8-2
api_version: 1
runtime: python

Expand All @@ -10,4 +10,4 @@ handlers:
script: antplanner.py
login: admin
- url: .*
script: antplanner.py
script: antplanner.py
66 changes: 65 additions & 1 deletion scraper.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from lib.BeautifulSoup import BeautifulSoup
import re
from django.utils import simplejson as json
import logging

def strip_search(html):
form_html = BeautifulSoup(html).find('form', action='http://websoc.reg.uci.edu/')
Expand Down Expand Up @@ -28,4 +30,66 @@ def strip_websoc_version(html):
return 'Couldn\'t find a match'
else:
return version_matches[0]


def get_rmp_error(title, message):
data = {
'name': title,
'href': 'javascript:void(0);',
'dept': message,
'ratings': '0',
'quality': '0',
'easiness': '0',
'hot': 'Ø'
}
return json.dumps(data)

def strip_professors(html, name):
table = BeautifulSoup(html).find('div', {'id': 'ratingTable'})
if table is None:
logging.debug(html[500:])
return get_rmp_error('Parse Error','Could not find "ratingTable" at RateMyProfessors.com')
else:
profs = list()
#name = name.upper()
split = name.split(',');
qLastName = split[0].strip()
qFirstName = split[1].strip()
if (qFirstName == None or qFirstName == ''):
qFirstName = '!'
rows = table.findAll('div', {'class': re.compile(r".*\bentry\b.*")})
for row in rows:
divName = row.find('div', {'class': 'profName'})
anchor = divName.find('a')
profName = unicode(anchor.renderContents().strip(), 'utf-8', 'ignore').upper()
split = profName.split(',');
lastName = split[0].strip()
firstName = split[1].strip()
if (firstName == None or firstName == ''):
firstName = '!'
#logging.debug(qLastName + ' =? ' + lastName + ' && ' + qFirstName + ' =? ' + firstName)
if lastName == qLastName and firstName[0] == qFirstName[0]:
href = 'http://www.ratemyprofessors.com/' + anchor['href'].strip()
profDept = row.find('div', {'class': 'profDept'}).renderContents().strip()
profRatings = row.find('div', {'class': 'profRatings'}).renderContents().strip()
profQuality = row.find('div', {'class': 'profAvg'}).renderContents().strip()
profEasiness = row.find('div', {'class': 'profEasy'}).renderContents().strip()
profHot = row.find('div', {'class': re.compile(r".*\bprofHot\b.*")}).renderContents().strip()
if profHot == 'Hot':
profHot = '✓'
else:
profHot = ' '

prof = {
'name': profName,
'href': href,
'dept': profDept,
'ratings': profRatings,
'quality': profQuality,
'easiness': profEasiness,
'hot': profHot
}
#logging.debug(prof)
profs.append(prof)
return json.dumps(profs)


16 changes: 16 additions & 0 deletions static/css/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,19 @@ iframe#school {
width: 50%;
float: left;
}

/* professor modal popup */
#prof-select {
font-size: 14px;
border-collapse: collapse;
margin:10px;
}
#prof-select td, #prof-select th {
border: 1px solid gray;
padding: 5px;
}

#prof-select a {
color: #688FE7;
font-size: 14px;
}
90 changes: 81 additions & 9 deletions static/js/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ function WindowManager() {
function SOCParser() {
this.SCHEDULE_CODE_INDEX = 0;
this.SCHEDULE_TYPE_INDEX = 1;
this.SCHEDULE_PROF_INDEX = 4;
this.SCHEDULE_TIME_INDEX = 5;

this.getTimeString = function(element) {
Expand All @@ -326,22 +327,23 @@ function SOCParser() {
};

this.getCourseCode = function(element) {
var courseCode = $(element).find('td').eq(this.SCHEDULE_CODE_INDEX).html();
return courseCode;
return $(element).find('td').eq(this.SCHEDULE_CODE_INDEX).html();
};

this.getCourseType = function(element) {
var courseType = $(element).find('td').eq(this.SCHEDULE_TYPE_INDEX).html();
return courseType;
return $(element).find('td').eq(this.SCHEDULE_TYPE_INDEX).html();
};

this.getCourseProf = function(element) {
return $(element).find('td').eq(this.SCHEDULE_PROF_INDEX).html();
}

this.getCourseString = function(element) {
var courseString = $(element).prevAll().find('.CourseTitle:last').html();
return courseString;
return $(element).prevAll().find('.CourseTitle:last').html();
}
};

function SOC() {
function SOC() {
this.initSOC = function(bridge) {
var list = $('.course-list', frames['school'].document);

Expand All @@ -355,7 +357,7 @@ function SOC() {
}
);

//click on course
//click on course (this should be placed on all tr's except instructor)
$("tr[valign*='top']", list).click(function() {
var socParser = new SOCParser();
var courseUtils = new CourseUtils();
Expand Down Expand Up @@ -402,6 +404,66 @@ function SOC() {
bridge.addEvent(calEvents[i]);
}
});

// click on instructor
$("tr[valign*='top'] td:nth-child(5)", list).click(function() {
var prof = $(this).html();
showProfessors(prof);
});

// instructor hover
$("tr[valign*='top'] td:nth-child(5)", list).hover(
function() {
$(this).css({'color': 'blue', 'cursor': 'pointer'});
},
function() {
$(this).css({'color': 'inherit', 'cursor': 'inherit'});
}
);
}
}

function showProfessors(nameString) {
// name is the query string for professors
var profTable = $('#prof-select');
profTable.html('<tr><td style="border:0">Please wait while we load RateMyProfessors.com</td></tr>');
profTable.dialog('open');

var trs = '<tr><th>Professor</th><th>Department</th><th>#&nbsp;Ratings</th><th>Quality</th><th>Easiness</th><th>Hot</th></tr>';
nameList = nameString.split('<br>');
for (var n=0; n<nameList.length; n++) {
name = nameList[n].toUpperCase();
if (name == '' || name == 'STAFF') {
trs += '<tr><td>'+name+'</td><td>&nbsp;</td><td>0 found</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>';
profTable.html(trs);
} else {
$.ajax({
url: "/prof",
type: 'get',
data: 'name=' + name,
dataType: 'json',
beforeSend: function() {
$('body').css({'cursor': 'wait'});
},
success: function(data) {
if (data.length > 0) {
for (var i=0; i<data.length; i++) {
var p = data[i];
trs += '<tr><td><a href="'+p.href+'" target="_blank">'+p.name+'</a></td><td>'+p.dept+'</td><td>'+p.ratings+'</td><td>'+p.quality+'</td><td>'+p.easiness+'</td><td>'+p.hot+'</td></tr>';
}
} else {
trs += '<tr><td>'+name+'</td><td>&nbsp;</td><td>0 found</td><td>&nbsp;</td><td>&nbsp;</td><td>&nbsp;</td></tr>';
}
profTable.html(trs);
},
error: function(jqXHR, textStatus, errorThrown) {
profTable.html('<tr><td>An error occured:</td></tr><tr><td>'+textStatus+'</td><td>'+errorThrown+'</td></tr>');
},
complete: function(jqXHR, textStatus) {
$('body').css({'cursor': 'auto'});
}
});
}
}
}

Expand Down Expand Up @@ -541,7 +603,17 @@ $(document).ready(function() {
});
return false;
});

$('#prof-select').dialog({ autoOpen: false,
modal: true,
title: 'RateMyProfessors.com',
width: 600,
resizable: false,
closeOnEscape: true,
draggable: false
});

});

//surprise!
if (top === self){}else{$(document).ready(function(){$('html').html('<center><img src="http://i.imgur.com/ANz8N.png"></center>')});}
if (top === self){}else{$(document).ready(function(){$('html').html('<center><img src="http://i.imgur.com/ANz8N.png"></center>')});}
8 changes: 7 additions & 1 deletion templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
<script type="text/javascript" src='/static/js/main.js'></script>

<script type="text/javascript">
/*
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-16581503-1']);
_gaq.push(['_trackPageview']);
Expand All @@ -25,6 +26,7 @@
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
*/
</script>

</head>
Expand Down Expand Up @@ -59,8 +61,12 @@ <h2>A better WebSoc for UCI </h2>
<div id="calendar">
</div>

<iframe src ="/search" id="school" name="school" frameBorder="0">
<iframe src="/search" id="school" name="school" frameBorder="0">
</iframe>

<table id="prof-select">
<tr><td>Please wait while we load RateMyProfessors.com</td></tr>
</table>

</div>
</body>
Expand Down