sfcsfs 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +52 -0
- data/Rakefile +10 -0
- data/lib/sfcsfs.rb +16 -0
- data/lib/sfcsfs/agent.rb +88 -0
- data/lib/sfcsfs/agent/navigations.rb +97 -0
- data/lib/sfcsfs/homework.rb +12 -0
- data/lib/sfcsfs/lecture.rb +125 -0
- data/lib/sfcsfs/util.rb +15 -0
- data/script/console +12 -0
- data/script/console_helper.rb +4 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/sfcsfs.gemspec +22 -0
- data/spec/sfcsfs_agent_spec.rb +84 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +8 -0
- data/tasks/add.rake +49 -0
- data/tasks/rspec.rake +20 -0
- metadata +124 -0
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 ymrl
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# SFCSFS
|
2
|
+
|
3
|
+
SFCSFS is a SFC-SFS Scraping Library. SFC-SFS is an internal website for Keio Univ. Shounan Fujisawa Campus.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'sfcsfs'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install sfcsfs
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
config = Pit.get("sfcsfs", :require => {
|
22
|
+
:account => "your CNS account",
|
23
|
+
:password => "your CNS password"
|
24
|
+
})
|
25
|
+
|
26
|
+
# Login to SFC-SFS
|
27
|
+
agent = SFCSFS.login(config[:account],config[:password])
|
28
|
+
|
29
|
+
# Get all classes of this semester and shows
|
30
|
+
# It takes several minutes...
|
31
|
+
list = agent.all_classes_of_this_semester
|
32
|
+
|
33
|
+
# Show name of these
|
34
|
+
list.each do |e|
|
35
|
+
puts e.title
|
36
|
+
end
|
37
|
+
|
38
|
+
# Get your current weekly schedule
|
39
|
+
list = agent.my_schedule
|
40
|
+
|
41
|
+
# Show name of these
|
42
|
+
list.each do |e|
|
43
|
+
puts e.title
|
44
|
+
end
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
|
48
|
+
1. Fork it
|
49
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
50
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
51
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
52
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/sfcsfs.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#coding:utf-8
|
2
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
3
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
4
|
+
|
5
|
+
directory = File.expand_path(File.dirname(__FILE__))
|
6
|
+
|
7
|
+
require directory+'/sfcsfs/lecture.rb'
|
8
|
+
require directory+'/sfcsfs/homework.rb'
|
9
|
+
require directory+'/sfcsfs/util.rb'
|
10
|
+
require directory+'/sfcsfs/agent.rb'
|
11
|
+
require directory+'/sfcsfs/agent/navigations.rb'
|
12
|
+
|
13
|
+
|
14
|
+
module SFCSFS
|
15
|
+
VERSION = '0.1.0'
|
16
|
+
end
|
data/lib/sfcsfs/agent.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
#coding:utf-8
|
2
|
+
require 'nokogiri'
|
3
|
+
require 'uri'
|
4
|
+
require 'net/https'
|
5
|
+
require 'addressable/uri'
|
6
|
+
|
7
|
+
module SFCSFS
|
8
|
+
REDIRECT_LIMIT = 5
|
9
|
+
|
10
|
+
class Agent
|
11
|
+
|
12
|
+
def inspect
|
13
|
+
"#{self.class} #{@id}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def request uri,method=:get,data={}
|
17
|
+
ret = nil
|
18
|
+
count = 0
|
19
|
+
while count < REDIRECT_LIMIT and !ret or Net::HTTPRedirection === ret
|
20
|
+
uri = (URI::Generic === uri ? uri : URI.parse(uri))
|
21
|
+
req = nil
|
22
|
+
uri += '/' if uri.path == ''
|
23
|
+
path = uri.path
|
24
|
+
path += "?#{uri.query}" if uri.query && uri.query.length > 0
|
25
|
+
if method.to_sym == :post
|
26
|
+
req = Net::HTTP::Post.new(path)
|
27
|
+
else
|
28
|
+
req = Net::HTTP::Get.new(path)
|
29
|
+
end
|
30
|
+
req.set_form_data(data) if data.length > 0
|
31
|
+
http = Net::HTTP.new(uri.host,uri.port)
|
32
|
+
http.use_ssl = true if uri.scheme == 'https'
|
33
|
+
http.start{|http| ret = http.request(req)}
|
34
|
+
@uri = uri
|
35
|
+
uri = ret['location'] if ret['location']
|
36
|
+
count += 0
|
37
|
+
end
|
38
|
+
if count >= REDIRECT_LIMIT
|
39
|
+
raise TooManyRedirectionsException
|
40
|
+
end
|
41
|
+
return ret
|
42
|
+
end
|
43
|
+
|
44
|
+
def request_parse uri,method=:get,data={}
|
45
|
+
uri = (URI::Generic === uri ? uri : URI.parse(uri))
|
46
|
+
r = request(uri,method,data)
|
47
|
+
@doc = Nokogiri.HTML(SFCSFS.convert_encoding(r.body),nil,'UTF-8')
|
48
|
+
if meta = @doc.search('meta[http-equiv=refresh]').first
|
49
|
+
match = meta.attr('content').match(/url=(.*)$/)
|
50
|
+
if match
|
51
|
+
request_parse(@uri+match[1])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
return @doc
|
55
|
+
end
|
56
|
+
|
57
|
+
def initialize
|
58
|
+
@uri = nil
|
59
|
+
@doc = nil
|
60
|
+
@id = nil
|
61
|
+
@base_uri = nil
|
62
|
+
@type = nil
|
63
|
+
return self
|
64
|
+
end
|
65
|
+
|
66
|
+
def Agent.login(account,passwd,options={})
|
67
|
+
a = Agent.new
|
68
|
+
doc = a.request_parse('https://gc.sfc.keio.ac.jp/sfc-sfs/')
|
69
|
+
action = doc.search('form').attr('action')
|
70
|
+
a.request_parse(action,:post,:u_login => account, :u_pass => passwd)
|
71
|
+
query_values = Addressable::URI.parse(a.uri).query_values
|
72
|
+
a.id = query_values['id']
|
73
|
+
a.type = query_values['type']
|
74
|
+
|
75
|
+
if options[:vu9]
|
76
|
+
a.base_uri = URI.parse('https://vu9.sfc.keio.ac.jp/')
|
77
|
+
else
|
78
|
+
a.base_uri = a.uri + '/'
|
79
|
+
end
|
80
|
+
|
81
|
+
return a
|
82
|
+
end
|
83
|
+
attr_accessor :login,:query_values,:base_uri,
|
84
|
+
:doc,:id,:uri,:type
|
85
|
+
end
|
86
|
+
class TooManyRedirectionsException < Exception
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
#coding:UTF-8
|
2
|
+
class SFCSFS::Agent
|
3
|
+
def plan_of_this_semester
|
4
|
+
get_plans_page_of_this_semester
|
5
|
+
plan_list_from_plans_page
|
6
|
+
end
|
7
|
+
|
8
|
+
def plan_of_next_semester
|
9
|
+
get_plans_page_of_next_semester
|
10
|
+
plan_list_from_plans_page
|
11
|
+
end
|
12
|
+
|
13
|
+
def all_classes_of_this_semester
|
14
|
+
get_plans_page_of_this_semester
|
15
|
+
all_classes_from_plans_page
|
16
|
+
end
|
17
|
+
|
18
|
+
def all_classes_of_next_semester
|
19
|
+
get_plans_page_of_next_semester
|
20
|
+
all_classes_from_plans_page
|
21
|
+
end
|
22
|
+
|
23
|
+
def get_plans_page_of_this_semester
|
24
|
+
outer_uri = @base_uri +
|
25
|
+
"/sfc-sfs/portal_s/s02.cgi?id=#{@id}&type=#{@type}&mode=1&lang=ja"
|
26
|
+
request_parse(outer_uri)
|
27
|
+
inner_uri = outer_uri + @doc.search('iframe').attr('src').to_s
|
28
|
+
request_parse(inner_uri)
|
29
|
+
end
|
30
|
+
|
31
|
+
def get_plans_page_of_next_semester
|
32
|
+
outer_uri = @base_uri +
|
33
|
+
"/sfc-sfs/portal_s/s02.cgi?id=#{@id}&type=#{@type}&mode=2&lang=ja"
|
34
|
+
request_parse(outer_uri)
|
35
|
+
inner_uri = outer_uri + @doc.search('iframe').attr('src').to_s
|
36
|
+
request_parse(inner_uri)
|
37
|
+
end
|
38
|
+
|
39
|
+
def all_classes_from_plans_page
|
40
|
+
list = []
|
41
|
+
uri = @uri
|
42
|
+
@doc.search('a[href]').to_a.delete_if{|e| !e.attr('href').match(/class_list\.cgi/)}.each do |e|
|
43
|
+
request_parse uri+e.attr('href')
|
44
|
+
@doc.search('a[href]').to_a.delete_if{|e| !e.attr('href').match(/plan_list\.cgi/)}.each do |e|
|
45
|
+
str = e.parent.text
|
46
|
+
title = nil
|
47
|
+
instructor = nil
|
48
|
+
#if match = str.match(/:\d+\(.+?\) …\s?(.+?)\s?\((.+?)\)…/)
|
49
|
+
if match = str.match(/:\d+\(.+?\) … (.+?)\s?\(([^\(\)]+?)\)…/u)
|
50
|
+
title = match[1]
|
51
|
+
instructor = match[2]
|
52
|
+
end
|
53
|
+
q = Addressable::URI.parse(e.attr('href')).query_values
|
54
|
+
ks = q['ks']
|
55
|
+
yc = q['yc']
|
56
|
+
reg = q['reg']
|
57
|
+
term = q['term']
|
58
|
+
list.push SFCSFS::Lecture.new(self,title,instructor,:ks=>ks,:yc=>yc,:reg=>reg,:term=>term)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
return list
|
62
|
+
end
|
63
|
+
|
64
|
+
def plan_list_from_plans_page
|
65
|
+
@doc.search('a').to_a.delete_if{|e| !e.attributes['href'].match(/syll_view.cgi/)}.map do |e|
|
66
|
+
href = e.attributes['href']
|
67
|
+
q = Addressable::URI.parse(href).query_values
|
68
|
+
ks = q['ks']
|
69
|
+
yc = q['yc']
|
70
|
+
title = e.children.first.to_s
|
71
|
+
SFCSFS::Lecture.new(self,title,nil,:ks=>ks,:yc=>yc)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def my_schedule
|
76
|
+
outer_uri = @base_uri +
|
77
|
+
"/sfc-sfs/portal_s/s01.cgi?id=#{@id}&type=#{@type}&mode=1&lang=ja"
|
78
|
+
request_parse outer_uri
|
79
|
+
inner_uri = @uri + @doc.search('iframe').attr('src').to_s
|
80
|
+
request_parse inner_uri
|
81
|
+
|
82
|
+
@doc.search('table a[href]').to_a.delete_if{|e|
|
83
|
+
!e.attr('href').match(/sfs_class/)
|
84
|
+
}.map do |e|
|
85
|
+
href = e.attr("href")
|
86
|
+
q = Addressable::URI.parse(href).query_values
|
87
|
+
option ={}
|
88
|
+
option[:ks] = q['ks']
|
89
|
+
option[:yc] = q['yc']
|
90
|
+
option[:mode] = href.match(/faculty/) ? 'faculty' : 'student'
|
91
|
+
title = e.children.first.to_s
|
92
|
+
title.gsub!(/\[([^\]]*)\]$/u){option[:place]=$1;""}
|
93
|
+
instructor = e.next.next.to_s.gsub(/[()\s ]/u,'')
|
94
|
+
SFCSFS::Lecture.new(self,title,instructor,option)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
#coding:utf-8
|
2
|
+
module SFCSFS
|
3
|
+
class Lecture
|
4
|
+
def initialize(agent,title,instructor,config={})
|
5
|
+
@agent = agent
|
6
|
+
@title = title
|
7
|
+
@instructor = instructor
|
8
|
+
@instructors = config[:instructors] || []
|
9
|
+
@mode = config[:mode]
|
10
|
+
@yc = config[:yc]
|
11
|
+
@ks = config[:ks]
|
12
|
+
@reg = config[:reg]
|
13
|
+
@term = config[:term]
|
14
|
+
@homeworks = config[:homeworks] || []
|
15
|
+
@periods = config[:periods] || []
|
16
|
+
@applicants = config[:applicants]
|
17
|
+
@limit = config[:limit]
|
18
|
+
@place = config[:place]
|
19
|
+
end
|
20
|
+
def inspect
|
21
|
+
"#{self.class} \"#{@title}\" \"#{@instructor}\" #{@yc} #{@ks}"
|
22
|
+
end
|
23
|
+
def class_top_path
|
24
|
+
unless @yc && @ks && @agent.id
|
25
|
+
raise NotEnoughParamsException
|
26
|
+
end
|
27
|
+
mode = 'student'
|
28
|
+
file = 's_class_top.cgi'
|
29
|
+
if(self.mode == 'faculty')
|
30
|
+
mode = 'faculty'
|
31
|
+
file = 'f_class_top.cgi'
|
32
|
+
end
|
33
|
+
return "/sfc-sfs/sfs_class/#{mode}/#{file}?lang=ja&ks=#{@ks}&yc=#{@yc}&id=#{@agent.id}"
|
34
|
+
end
|
35
|
+
def stay_input_path
|
36
|
+
unless @yc && @ks && @agent.id
|
37
|
+
raise NotEnoughParamsException
|
38
|
+
end
|
39
|
+
"/sfc-sfs/sfs_class/stay/stay_input.cgi?yc=#{@yc}&ks=#{@ks}&enc_id=#{@agent.id}"
|
40
|
+
end
|
41
|
+
def student_selection_path
|
42
|
+
unless @yc && @agent.id
|
43
|
+
raise NotEnoughParamsException
|
44
|
+
end
|
45
|
+
"/sfc-sfs/sfs_class/student/view_student_select.cgi?enc_id=#{@agent.id}&yc=#{@yc}&lang=ja"
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_detail
|
49
|
+
uri = @agent.base_uri + class_top_path
|
50
|
+
doc = @agent.request_parse(uri)
|
51
|
+
@title = doc.search('h3.one').first.children.first.to_s.gsub(/[\s ]/,'')
|
52
|
+
@instructors += doc.search('h3.one > a[href]').to_a.delete_if{|e| !e.attr('href').match(/profile\.cgi/)}.map{|e|e.children.first.to_s}
|
53
|
+
@instructors.uniq!
|
54
|
+
term = doc.search('h3.one .ja').text.match(/時限:(\d{4})年([春秋])学期(.*)$/)
|
55
|
+
if term
|
56
|
+
@term = "#{term[1]}#{term[2] == '春' ? 's' : 'f'}"
|
57
|
+
@periods += term[3].gsub(/\s/,'').split(/,/)
|
58
|
+
@periods.uniq!
|
59
|
+
end
|
60
|
+
page = doc.to_s
|
61
|
+
#a.doc.search('a').to_a.delete_if{|e|!e.attributes['href'].match(%r{/report/report\.cgi\?})}.each do |e|
|
62
|
+
# # TODO : Homeworks Func
|
63
|
+
#end
|
64
|
+
if m = page.match(/履修希望者数:(\d+)/)
|
65
|
+
@applicants = m[1].to_i
|
66
|
+
end
|
67
|
+
if m = page.match(/受入学生数(予定):約 (\d+) 人/)
|
68
|
+
@limit = m[1].to_i
|
69
|
+
end
|
70
|
+
return self
|
71
|
+
end
|
72
|
+
|
73
|
+
def student_selection_list
|
74
|
+
uri = @agent.base_uri + student_selection_path
|
75
|
+
doc = @agent.request_parse(uri)
|
76
|
+
return doc.search('tr[bgcolor="#efefef"] td').map{|e| e.children.first.to_s}.delete_if{|e| !e.match(/^\d{8}/)}
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_stay_input_page
|
80
|
+
uri = @agent.base_uri + stay_input_path
|
81
|
+
@agent.request_parse(uri)
|
82
|
+
end
|
83
|
+
def submit_stay_form data
|
84
|
+
param = {}
|
85
|
+
uri = @agent.base_uri + '/sfc-sfs/sfs_class/stay/stay_input.cgi'
|
86
|
+
unless @yc && @ks && @aget.id
|
87
|
+
raise NotEnoughParamsException
|
88
|
+
end
|
89
|
+
param[:stay_phone] = data[:stay_phone]
|
90
|
+
param[:stay_p_phone] = data[:stay_p_phone]
|
91
|
+
param[:stay_time] = data[:stay_time]
|
92
|
+
param[:selectRoom] = data[:selectRoom]
|
93
|
+
param[:selectFloor] = data[:selectFloor]
|
94
|
+
param[:stay_room_other] = data[:stay_room_other]
|
95
|
+
param[:stay_reason] = data[:stay_reason]
|
96
|
+
param[:mode] = 'submit'
|
97
|
+
param[:yc] = @yc
|
98
|
+
param[:ks] = @ks
|
99
|
+
param[:enc_id] = @agent.id
|
100
|
+
request uri,:post,data
|
101
|
+
end
|
102
|
+
def add_to_plan
|
103
|
+
unless @reg && @yc && @ks && @agent.id && @term
|
104
|
+
raise NotEnoughParamsException
|
105
|
+
end
|
106
|
+
uri = @agent.base_uri + "/sfc-sfs/sfs_class/student/plan_list.cgi?reg=#{@reg}&yc=#{@yc}&mode=add&ks=#{@ks}&id=#{@agent.id}&term=#{@term}&lang=ja"
|
107
|
+
@agent.request(uri)
|
108
|
+
end
|
109
|
+
|
110
|
+
def delete_from_plan
|
111
|
+
unless @yc && @ks && @agent.id && @term
|
112
|
+
raise NotEnoughParamsException
|
113
|
+
end
|
114
|
+
uri = @agent.base_uri + "/sfc-sfs/sfs_class/student/plan_list.cgi?reg=#{@reg}&yc=#{@yc}&mode=del&ks=#{@ks}&id=#{@agent.id}&term=#{@term}&lang=ja"
|
115
|
+
@agent.request(uri)
|
116
|
+
end
|
117
|
+
|
118
|
+
attr_accessor :title,:instructor,:mode,:yc,:ks,:homeworks,
|
119
|
+
:add_list_url,:periods,:applicants,:limit,
|
120
|
+
:reg,:term, :place
|
121
|
+
end
|
122
|
+
|
123
|
+
class NotEnoughParamsException < Exception
|
124
|
+
end
|
125
|
+
end
|
data/lib/sfcsfs/util.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module SFCSFS
|
2
|
+
def SFCSFS.login(account,passwd)
|
3
|
+
return Agent.login(account,passwd)
|
4
|
+
end
|
5
|
+
|
6
|
+
def SFCSFS.convert_encoding str
|
7
|
+
if RUBY_VERSION >= "1.9"
|
8
|
+
return str.force_encoding(Encoding::EUC_JP).encode(Encoding::UTF_8,:invalid=>:replace,:undef=>:replace)
|
9
|
+
else
|
10
|
+
require 'kconv'
|
11
|
+
return Kconv.kconv(str,Kconv::UTF8,Kconv::EUC)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
data/script/console
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r ./#{File.dirname(__FILE__) + '/../lib/sfcsfs'}"
|
9
|
+
libs << " -r ./#{File.dirname(__FILE__) + '/console_helper'}"
|
10
|
+
puts "Loading SFCSFS"
|
11
|
+
puts "SFCSFS::Agent.login(CONFIG[:account],CONFIG[:password])"
|
12
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
data/sfcsfs.gemspec
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/sfcsfs', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["ymrl"]
|
6
|
+
gem.email = ["ymrl@ymrl.net"]
|
7
|
+
gem.description = %q{SFC-SFS Scraping Library}
|
8
|
+
gem.summary = %q{SFC-SFS Scraping Library}
|
9
|
+
gem.homepage = ""
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "sfcsfs"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = SFCSFS::VERSION
|
17
|
+
gem.add_dependency('nokogiri','~> 1.5.5')
|
18
|
+
gem.add_dependency('addressable','~> 2.2.8')
|
19
|
+
gem.add_development_dependency('rspec', '~> 2.10.0')
|
20
|
+
gem.add_development_dependency('rake')
|
21
|
+
gem.add_development_dependency('pit')
|
22
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
#coding:utf-8
|
2
|
+
|
3
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
4
|
+
require File.dirname(__FILE__) + '/../lib/sfcsfs.rb'
|
5
|
+
|
6
|
+
describe 'Agent' do
|
7
|
+
before do
|
8
|
+
config = Pit.get("sfcsfs", :require => {
|
9
|
+
:account => "your CNS account",
|
10
|
+
:password => "your CNS password"
|
11
|
+
})
|
12
|
+
@agent = SFCSFS.login(config[:account],config[:password])
|
13
|
+
end
|
14
|
+
it 'URLがs01.cgiにいる' do
|
15
|
+
@agent.uri.to_s.match(%r!^https://vu.\.sfc\.keio\.ac\.jp/sfc-sfs/portal_s/s01\.cgi.*!).should be_true
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'idがセットされている' do
|
19
|
+
@agent.id.should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
#it '次学期プランページへのアクセス' do
|
23
|
+
# @agent.get_plans_page_of_next_semester
|
24
|
+
#end
|
25
|
+
|
26
|
+
#context '次学期プランの履修' do
|
27
|
+
# it '科目一覧の取得' do
|
28
|
+
# list = @agent.get_class_list_of_next_semester
|
29
|
+
# list.each do |e|
|
30
|
+
# e.should be_instance_of(SFCSFS::Lecture)
|
31
|
+
# e.add_list_url.should be_true
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#end
|
35
|
+
#it '今学期プランページへのアクセス' do
|
36
|
+
# @agent.get_plans_page_of_this_semester
|
37
|
+
#end
|
38
|
+
|
39
|
+
#context '今学期プランの履修' do
|
40
|
+
# it '科目一覧の取得' do
|
41
|
+
# list = @agent.get_class_list_of_this_semester
|
42
|
+
# list.each do |e|
|
43
|
+
# e.should be_instance_of(SFCSFS::Lecture)
|
44
|
+
# e.add_list_url.should be_true
|
45
|
+
# end
|
46
|
+
# end
|
47
|
+
#end
|
48
|
+
|
49
|
+
|
50
|
+
context 'my時間割にアクセスする' do
|
51
|
+
before do
|
52
|
+
@lectures = @agent.my_schedule
|
53
|
+
end
|
54
|
+
it 'Lectureが生成されている' do
|
55
|
+
@lectures.each do |e|
|
56
|
+
e.should be_instance_of(SFCSFS::Lecture)
|
57
|
+
e.instructor.should have_at_least(1).items
|
58
|
+
e.yc.should be_true
|
59
|
+
e.ks.should be_true
|
60
|
+
e.mode.should be_true
|
61
|
+
e.homeworks.should be_instance_of(Array)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
#it 'Lectureから残留届けページヘ行ける' do
|
65
|
+
# @lectures.each {|e| e.get_stay_input_page(@agent)}
|
66
|
+
#end
|
67
|
+
it 'Lecture#instructorが括弧とか\sとか含まない' do
|
68
|
+
@lectures.each { |e| (e.instructor.match(/[()()\s]/)).should be_false }
|
69
|
+
end
|
70
|
+
#it 'Lectureそれぞれに詳細情報を取得できる' do
|
71
|
+
# @lectures.each do |e| e.get_detail()
|
72
|
+
# e.homeworks.each do |h|
|
73
|
+
# h.should be_instance_of(SFCSFS::Homework)
|
74
|
+
# h.title.should have_at_least(1).items
|
75
|
+
# h.title.match(/^「/).should be_false
|
76
|
+
# h.title.match(/」$/).should be_false
|
77
|
+
# h.url.match(%r{.*\.sfc\.keio\.ac\.jp/sfc-sfs/sfs_class/report/report.cgi\?}).should be_true
|
78
|
+
# end
|
79
|
+
# end
|
80
|
+
#end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
data/tasks/add.rake
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require './' + File.dirname(__FILE__) + '/../lib/sfcsfs.rb'
|
2
|
+
require 'pit'
|
3
|
+
desc "Add All Lectures of Next Semester"
|
4
|
+
|
5
|
+
task :addnext do
|
6
|
+
config = Pit.get("sfcsfs", :require => {
|
7
|
+
:account => "your CNS account",
|
8
|
+
:password => "your CNS password"
|
9
|
+
})
|
10
|
+
agent = SFCSFS.login(config[:account],config[:password])
|
11
|
+
list = agent.all_classes_of_next_semester
|
12
|
+
list.each do |lecture|
|
13
|
+
puts "#{lecture.title} (#{lecture.instructor})"
|
14
|
+
retry_count = 0
|
15
|
+
begin
|
16
|
+
lecture.add_to_plan
|
17
|
+
rescue
|
18
|
+
sleep 60
|
19
|
+
retry_count += 1
|
20
|
+
if retry_count < 10
|
21
|
+
retry
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Add All Lectures of this Semester"
|
28
|
+
task :addall do
|
29
|
+
config = Pit.get("sfcsfs", :require => {
|
30
|
+
:account => "your CNS account",
|
31
|
+
:password => "your CNS password"
|
32
|
+
})
|
33
|
+
agent = SFCSFS.login(config[:account],config[:password])
|
34
|
+
list = agent.all_classes_of_this_semester
|
35
|
+
list.each do |lecture|
|
36
|
+
puts "#{lecture.title} (#{lecture.instructor})"
|
37
|
+
retry_count = 0
|
38
|
+
begin
|
39
|
+
lecture.add_to_plan
|
40
|
+
rescue
|
41
|
+
sleep 60
|
42
|
+
retry_count += 1
|
43
|
+
if retry_count < 10
|
44
|
+
retry
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
data/tasks/rspec.rake
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
begin
|
2
|
+
require 'rspec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
+
require 'rspec'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
rescue LoadError
|
10
|
+
puts <<-EOS
|
11
|
+
To use rspec for testing you must install rspec gem:
|
12
|
+
gem install rspec
|
13
|
+
EOS
|
14
|
+
exit(0)
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec::Core::RakeTask.new do |t|
|
18
|
+
t.rspec_opts = ['--options', "spec/spec.opts"]
|
19
|
+
t.pattern = 'spec/**/*_spec.rb'
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sfcsfs
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- ymrl
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-20 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogiri
|
16
|
+
requirement: &87235160 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.5.5
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *87235160
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: addressable
|
27
|
+
requirement: &87234920 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.2.8
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *87234920
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: rspec
|
38
|
+
requirement: &87234690 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 2.10.0
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *87234690
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: &87234500 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *87234500
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: pit
|
60
|
+
requirement: &87234270 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *87234270
|
69
|
+
description: SFC-SFS Scraping Library
|
70
|
+
email:
|
71
|
+
- ymrl@ymrl.net
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/sfcsfs.rb
|
82
|
+
- lib/sfcsfs/agent.rb
|
83
|
+
- lib/sfcsfs/agent/navigations.rb
|
84
|
+
- lib/sfcsfs/homework.rb
|
85
|
+
- lib/sfcsfs/lecture.rb
|
86
|
+
- lib/sfcsfs/util.rb
|
87
|
+
- script/console
|
88
|
+
- script/console_helper.rb
|
89
|
+
- script/destroy
|
90
|
+
- script/generate
|
91
|
+
- sfcsfs.gemspec
|
92
|
+
- spec/sfcsfs_agent_spec.rb
|
93
|
+
- spec/spec.opts
|
94
|
+
- spec/spec_helper.rb
|
95
|
+
- tasks/add.rake
|
96
|
+
- tasks/rspec.rake
|
97
|
+
homepage: ''
|
98
|
+
licenses: []
|
99
|
+
post_install_message:
|
100
|
+
rdoc_options: []
|
101
|
+
require_paths:
|
102
|
+
- lib
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
104
|
+
none: false
|
105
|
+
requirements:
|
106
|
+
- - ! '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
requirements: []
|
116
|
+
rubyforge_project:
|
117
|
+
rubygems_version: 1.8.11
|
118
|
+
signing_key:
|
119
|
+
specification_version: 3
|
120
|
+
summary: SFC-SFS Scraping Library
|
121
|
+
test_files:
|
122
|
+
- spec/sfcsfs_agent_spec.rb
|
123
|
+
- spec/spec.opts
|
124
|
+
- spec/spec_helper.rb
|