Skip to content

Commit

Permalink
Merge pull request #86 from styfle/master
Browse files Browse the repository at this point in the history
Ratings from RateMyProfessors.com
  • Loading branch information
gumho committed Aug 27, 2011
2 parents eabd6f9 + 76d0606 commit ea66593
Show file tree
Hide file tree
Showing 6 changed files with 199 additions and 15 deletions.
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

0 comments on commit ea66593

Please sign in to comment.