2014-02-11 2 views
1
#!/usr/bin/ruby 
# Fetches all Virginia Tech classes from the timetable and spits them out into a nice JSON object 
# Can be run with option of which file to save output to or will save to classes.json by default 
require 'rubygems' 
require 'mechanize' 
require 'nokogiri' 
require 'json' 

#Create Mechanize Browser and Class Data hash to load data into 
agent = Mechanize.new 
classData = Hash.new 

#Get Subjects from Timetable page 
page = agent.get("https://banweb.banner.vt.edu/ssb/prod/HZSKVTSC.P_ProcRequest") 
subjects = page.forms.first.field_with(:name => 'subj_code').options 

#Loop subjects 
subjects.each do |subject| 

#Get the Timetable Request page & Form 
timetableSearch = agent.get("https://banweb.banner.vt.edu/ssb/prod/HZSKVTSC.P_ProcRequest") 
searchDetails = page.forms.first 

#Submit with specific subject 
searchDetails.set_fields({ 
    :SUBJ_CODE => subject, 
    :TERMYEAR => '201401', 
    :CAMPUS => 0 
}) 

#Submit the form and store results into courseListings 
courseListings = Nokogiri::HTML(
    searchDetails.submit(searchDetails.buttons[0]).body 
) 

#Create Array in Hash to store all classes for subjects 
classData[subject] = [] 

#For every Class 
courseListings.css('table.dataentrytable/tr').collect do |course| 

    subjectClassesDetails = Hash.new 

    #Map Table Cells for each course to appropriate values 
    [ 
     [ :crn, 'td[1]/p/a/b/text()'], 
     [ :course, 'td[2]/font/text()'], 
     [ :title, 'td[3]/text()'], 
     [ :type, 'td[4]/p/text()'], 
     [ :hrs, 'td[5]/p/text()'], 
     [ :seats, 'td[6]/text()'], 
     [ :instructor, 'td[7]/text()'], 
     [ :days, 'td[8]/text()'], 
     [ :begin, 'td[9]/text()'], 
     [ :end, 'td[10]/text()'], 
     [ :location, 'td[11]/text()'], 
    # [ :exam, 'td[12]/text()'] 
    ].collect do |name, xpath| 
     #Not an additional time session (2nd row) 
     if (course.at_xpath('td[1]/p/a/b/text()').to_s.strip.length > 2) 
      subjectClassesDetails[name] = course.at_xpath(xpath).to_s.strip 
     end 
    end 

    #Add class to Array for Subject! 
    classData[subject].push(subjectClassesDetails) 
end 
end 

#Write Data to JSON file 
open(ARGV[0] || "classes.json", 'w') do |file| 
file.print JSON.pretty_generate(classData) 
end 

Приведенный выше код должен извлекать данные из https://banweb.banner.vt.edu/ssb/prod/HZSKVTSC.P_ProcRequest , но если я печатаю subjects.length это печатает 0, так что явно не получать правильные данные. Данный код термина «201401» определенно является правильным.рубин Script не удалось собрать данные

Я заметил, что когда я вручную вводил ссылку на мой браузер, поле subject не позволяет вам выбирать параметр до тех пор, пока не будет выбран термин, однако, когда я просматриваю источник страницы, данные явно уже есть , Что я могу сделать, чтобы получить эти данные?

ответ

0

Я смотрю эту страницу vtech, и я вижу, что вам нужно выбрать TERMYEAR прежде, чем выпадающие окна subj_code позволят вам получить варианты. К сожалению, это происходит с javascript в function dropdownlist(listindex). Механизм не обрабатывает javascript, поэтому этот скрипт обречен на провал.

Ваши варианты для запуска браузера Automator, как Watir или селеном: обсуждается здесь: How do I use Mechanize to process JavaScript?

Или прочитать источник этой страницы и разобрать значения этих строк:

document.ttform.subj_code.options[0]=new Option("All Subjects","%",false, false); 
document.ttform.subj_code.options[1]=new Option("AAEC - Agricultural and Applied Economics","AAEC",false, false); 
document.ttform.subj_code.options[2]=new Option("ACIS - Accounting and Information Systems","ACIS",false, false); 

К получить варианты. Вы можете сделать это, просто используя open-uri:

require 'open-uri' 
page = open("https://banweb.banner.vt.edu/ssb/prod/HZSKVTSC.P_ProcRequest") 
page_source = page.read 

Теперь вы можете использовать регулярное выражение для поиска всех вариантов:

page_source.scan /document\.ttform.+;/ 

Это даст вам массив со всеми линиями, преследующих javascript-коды, содержащие параметры. Создайте регулярное выражение немного лучше, и вы можете извлечь текст опции из них. Я посмотрю, смогу ли я придумать что-нибудь для этого, и я отправлю обратно. Надеюсь, это заставит вас идти в правильном направлении.

Я вернулся. Я был в состоянии разобрать все варианты subj_code с этим регулярным выражением:

subjects = page_source.scan(/Option\("(.*?)"/).uniq # remove duplicates 
subjects.shift # get rid of the first option because it's just "All Subjects" 
subjects.size == 137 

Надежда, что помогает.

+0

Невозможно выбрать термин, который я хочу, изменив значение формы, а затем позвольте ему перезагрузить себя? –

+0

Нет, глядя на источник страницы, я вижу, что subj_code заполняется только через javascript. – DiegoSalazar

+0

И как уже упоминалось, Mechanize не обрабатывает javascript. Вы не сможете заставить этот скрипт работать с ним. Вам придется переключиться на один из вышеупомянутых камней. – DiegoSalazar

Смежные вопросы