nicoscraper 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +112 -0
- data/VERSION +1 -1
- data/lib/connector.rb +305 -304
- data/lib/converter.rb +3 -3
- data/lib/movie.rb +7 -7
- data/lib/mylist.rb +11 -11
- data/lib/nicos.rb +9 -0
- data/lib/parser.rb +11 -13
- data/lib/searcher.rb +130 -129
- data/nicoscraper.gemspec +5 -4
- data/test/movie_spec.rb +9 -11
- metadata +5 -4
- data/test/helper.rb +0 -18
- data/test/test_nicoscraper.rb +0 -7
data/README.md
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
#どんなライブラリか
|
2
|
+
ニコニコ動画から動画およびマイリスト情報を取得し、その情報に対して各種操作を行えます。タグやマイリスト検索結果からの抽出、および抽出結果に対する反復処理を行うメソッドも備え、ランキングサイト等の制作を支援します。
|
3
|
+
|
4
|
+
#簡単な概要
|
5
|
+
Movieクラス、Mylistクラス、Searcherモジュールから主要な機能が構成されています。基本的には、動画やマイリストのIDを指定してインスタンスを作り、そこから詳細な情報を取得するためのメソッドを実行したのち、さらに分析や加工を行う別のメソッドを実行する、という手順を踏みます。
|
6
|
+
|
7
|
+
##動画情報の取得
|
8
|
+
|
9
|
+
例えば"sm1097445"という動画IDから、タイトルや動画の長さ、現在の閲覧数等の詳細な情報を知りたいときは、
|
10
|
+
|
11
|
+
~~~~
|
12
|
+
require 'nicoscraper'
|
13
|
+
|
14
|
+
movie = Nicos::Movie::new("sm1097445")
|
15
|
+
movie.getInfo
|
16
|
+
|
17
|
+
p movie
|
18
|
+
|
19
|
+
<Nicos::Movie:0x00000002537aa8
|
20
|
+
@video_id="sm1097445",
|
21
|
+
@available=false, @title="【初音ミク】みくみくにしてあげる♪【してやんよ】",
|
22
|
+
@description="おまえら、みっくみくにしてやんよ。歌詞はhttp://ikamo.hp.infoseek.co.jp/mikumiku.txt(9/20 1:55修正)。上げている他のもの→mylist/1450136",
|
23
|
+
@thumbnail_url="http://tn-skr2.smilevideo.jp/smile?i=1097445",
|
24
|
+
@first_retrieve=1190218922,
|
25
|
+
@length=99,
|
26
|
+
@movie_type="flv",
|
27
|
+
@size_high=3906547,
|
28
|
+
@size_low=1688098,
|
29
|
+
@view_counter=9073614,
|
30
|
+
@comment_num=2553366,
|
31
|
+
@mylist_counter=183470,
|
32
|
+
@last_res_body="★███████████☆ ☆████████████●●●●███ ★█████... ",
|
33
|
+
@watch_url="http://www.nicovideo.jp/watch/sm1097445", @thumb_type="video",
|
34
|
+
@embeddable=1,
|
35
|
+
@no_live_play=0,
|
36
|
+
@tags_jp=["音楽", "初音ミク", "みくみくにしてあげる♪", "ミクオリジナル曲", "ika", "VOCALOID殿堂入り", "元気が出るミクうた", "VOCALOID", "初音ミク名曲リンク", "深夜みっく"],
|
37
|
+
@tags_tw=["彈幕強大", "把你MikuMiku掉♪", "週刊vocaloid排行榜第1名獲得曲", "翻譯歌曲", "台灣VOCALOID評論人氣曲", "最強彈幕傳說", "初音未來"],
|
38
|
+
@user_id=70391 >
|
39
|
+
|
40
|
+
~~~~
|
41
|
+
|
42
|
+
このように、Movieクラスのインスタンス(以下「動画インスタンス」)のgetInfoメソッドを利用します。その結果、動画インスタンスにインスタンス変数として各種情報が付加されます。
|
43
|
+
|
44
|
+
##マイリスト情報の取得
|
45
|
+
Mylistクラスもほぼ同様ですが、Mylistクラスのインスタンス(以下「マイリストインスタンス」)は、マイリスト情報の他に、そのマイリストが含む動画のインスタンスを自動的に生成します。つまり、
|
46
|
+
|
47
|
+
~~~~
|
48
|
+
require 'nicoscraper'
|
49
|
+
|
50
|
+
mylist = Nicos::Mylist::new("")
|
51
|
+
mylist.getInfoLt
|
52
|
+
|
53
|
+
p mylist
|
54
|
+
|
55
|
+
# 結果
|
56
|
+
#<Nicos::Mylist:0x00000002884670
|
57
|
+
@mylist_id=15196568,
|
58
|
+
@movies=[
|
59
|
+
#<Nicos::Movie:0x0000000255a968
|
60
|
+
@video_id="sm8481759",
|
61
|
+
@available=true, @title="【Oblivion】おっさんの大冒険1(ゆっくり実況)",
|
62
|
+
...
|
63
|
+
#<Nicos::Movie:0x0000000251a6b0
|
64
|
+
@video_id="sm8506034",
|
65
|
+
@available=true,
|
66
|
+
@title="【Oblivion】おっさんの大冒険2(ゆっくり実況)",
|
67
|
+
...
|
68
|
+
],
|
69
|
+
@available=true,
|
70
|
+
@title="【Oblivion】おっさんの大冒険",
|
71
|
+
... >
|
72
|
+
~~~~
|
73
|
+
|
74
|
+
というように、動画インスタンスを勝手につくりだして配列として保持します。
|
75
|
+
|
76
|
+
##検索結果の取得
|
77
|
+
|
78
|
+
タグやマイリスト検索結果からの情報取得には、Searcherモジュールを使います。情報のソート方法の指定、取得する範囲の制限が可能です。
|
79
|
+
|
80
|
+
~~~~
|
81
|
+
require 'nicoscraper'
|
82
|
+
|
83
|
+
t = Time.now
|
84
|
+
ytd = Date::new(t.year, t.month, t.day) - 1
|
85
|
+
yesterday = Time.local(ytd.year, ytd.month, ytd.day, 0, 0, 0).to_i
|
86
|
+
|
87
|
+
Searcher.byTag('ゆっくり実況プレイpart1リンク', 'post_new', nil) {
|
88
|
+
|result, page|
|
89
|
+
|
90
|
+
result.each { |e|
|
91
|
+
movie = Nicos::Movie.new(e['video_id'])
|
92
|
+
movie.getInfo
|
93
|
+
|
94
|
+
puts movie.title.toutf8 +
|
95
|
+
" is posted at " +
|
96
|
+
Time.at(movie.first_retrieve).to_s.toutf8
|
97
|
+
|
98
|
+
true if movie.first_retrieve <= yesterday
|
99
|
+
}
|
100
|
+
}
|
101
|
+
~~~~
|
102
|
+
|
103
|
+
これは'ゆっくり実況プレイpart1リンク'というタグの付く動画を、post_new=投稿日時が新しい順からさかのぼって取得していき、取得した動画の日付が前日の0時0分を超えるまでそれを続けます。
|
104
|
+
|
105
|
+
ブロック内の第1引数には取得結果が与えられるのですが、これは動画1つ毎のコールバックではなく、32個分の配列です。なぜ32個のセットなのかと言うと、ご存知のようにニコニコ動画の検索画面はページで区切られており、Searcherモジュールの各メソッドはページ毎に情報を取得するためです。Htmlから取得するにしろAtomフィードから取得するにしろ、1ページに32個の動画情報が含まれています。そして、第2引数にはそのページ数が与えられます。
|
106
|
+
|
107
|
+
なお、ブロック内でtrueを返すことによりスクレイプは終わります。逆に言えば、trueを返さない限り検索結果全ての情報を取得しようとするため、十分に注意して下さい。上の例では、取得した動画の日付を調べ、3日前の0時0分より前の動画があればそこでループを終える設計です。
|
108
|
+
|
109
|
+
|
110
|
+
#より詳しい情報
|
111
|
+
|
112
|
+
は、こちらを御覧下さい。
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.2
|
data/lib/connector.rb
CHANGED
@@ -5,356 +5,357 @@ require 'rubygems'
|
|
5
5
|
require 'ruby-debug'
|
6
6
|
require 'net/http'
|
7
7
|
|
8
|
+
module Nicos::Connector
|
9
|
+
class Connector
|
10
|
+
def initialize
|
11
|
+
# デフォルトのウェイト設定
|
12
|
+
@seqTime = 0
|
8
13
|
|
9
|
-
|
10
|
-
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
'timedOut' => {
|
38
|
-
'retryLimit' => 3,
|
39
|
-
'wait' => 10
|
14
|
+
@waitConfig = {
|
15
|
+
'seqAccLimit' => 10, # 連続してリクエストする回数
|
16
|
+
'afterSeq' => 10, # 連続リクエスト後のウェイト
|
17
|
+
'each' => 1, # 連続リクエスト時の、1リクエスト毎のウェイト
|
18
|
+
|
19
|
+
'increment' => 1, # アクセス拒絶時の、次回以降の1リクエスト毎のウェイトの増加量
|
20
|
+
'' => 100,
|
21
|
+
|
22
|
+
'deniedSeqReq'=> {
|
23
|
+
'retryLimit' => 3,
|
24
|
+
'wait' => 120
|
25
|
+
},
|
26
|
+
|
27
|
+
'serverIsBusy'=> {
|
28
|
+
'retryLimit' => 3,
|
29
|
+
'wait' => 120
|
30
|
+
},
|
31
|
+
|
32
|
+
'serviceUnavailable' => {
|
33
|
+
'retryLimit' => 3,
|
34
|
+
'wait' => 120
|
35
|
+
},
|
36
|
+
|
37
|
+
'timedOut' => {
|
38
|
+
'retryLimit' => 3,
|
39
|
+
'wait' => 10
|
40
|
+
}
|
40
41
|
}
|
41
|
-
}
|
42
42
|
|
43
|
-
|
44
|
-
|
43
|
+
@result = {}
|
44
|
+
end
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
46
|
+
private
|
47
|
+
|
48
|
+
def notPublic
|
49
|
+
# マイリスト非公開のときに403になる。後で専用の処理を入れるべき。
|
50
|
+
puts "This movie/mylist is not public."
|
51
|
+
@result = "notPublic"
|
52
|
+
return { "order" => "terminate" }
|
53
|
+
end
|
54
54
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
55
|
+
def limInCommunity
|
56
|
+
puts "This movie/mylist is limited in comunity members."
|
57
|
+
# ex. item_id -> 1294702905
|
58
|
+
@result = "limInCommunity"
|
59
|
+
return { "order" => "terminate" }
|
60
|
+
end
|
61
61
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
def notFound
|
63
|
+
puts "This movie/mylist is not found."
|
64
|
+
@result = "notFound"
|
65
|
+
return { "order" => "terminate" }
|
66
|
+
end
|
67
67
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
68
|
+
def deleted
|
69
|
+
puts "This movie/mylist is deleted."
|
70
|
+
@result = "deleted"
|
71
|
+
return { "order" => "terminate" }
|
72
|
+
end
|
73
73
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
74
|
+
def deniedSeqReq
|
75
|
+
puts "Denied sequential requests."
|
76
|
+
sleep @waitConfig["deniedSeqReq"]
|
77
|
+
@result = "deniedSeqReq"
|
78
|
+
return { "order" => "retry" }
|
79
|
+
end
|
80
80
|
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
81
|
+
def serverIsBusy
|
82
|
+
puts "The server is busy."
|
83
|
+
sleep @waitConfig["serverIsBusy"]
|
84
|
+
@result = "serverIsBusy"
|
85
|
+
return { "order" => "retry" }
|
86
|
+
end
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
88
|
+
def serviceUnavailable
|
89
|
+
puts "Service unavailable."
|
90
|
+
sleep @waitConfig["serviceUnavailable"]
|
91
|
+
@result = "serviceUnavailable"
|
92
|
+
return { "order" => "retry" }
|
93
|
+
end
|
94
94
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
95
|
+
def timedOut
|
96
|
+
puts "Request timed out."
|
97
|
+
sleep @waitConfig["timedOut"]
|
98
|
+
@result = "timedOut"
|
99
|
+
return { "order" => "retry" }
|
100
|
+
end
|
101
101
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
102
|
+
def success(resBody)
|
103
|
+
sleep @waitConfig["each"]
|
104
|
+
@seqTime += 1
|
105
|
+
|
106
|
+
if @seqTime >= @waitConfig["seqAccLimit"]
|
107
|
+
sleep @waitConfig["afterSeq"]
|
108
|
+
@seqTime = 0
|
109
|
+
end
|
110
|
+
return { "order" => "success", "body" => resBody }
|
109
111
|
end
|
110
|
-
return { "order" => "success", "body" => resBody }
|
111
|
-
end
|
112
112
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
113
|
+
def wait(status)
|
114
|
+
puts "Wait for " + waitTime + " second."
|
115
|
+
sleep @waitConfig[status.to_s]
|
116
|
+
end
|
117
|
+
|
118
|
+
public
|
119
119
|
|
120
|
-
|
121
|
-
|
122
|
-
|
120
|
+
def setWait(waitConfig)
|
121
|
+
if waitConfig != nil
|
122
|
+
@waitConfig = mixin(@waitConfig, waitConfig)
|
123
|
+
end
|
123
124
|
end
|
124
125
|
end
|
125
|
-
end
|
126
126
|
|
127
127
|
|
128
|
-
class
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
128
|
+
class Xml < Connector
|
129
|
+
def get (host, entity)
|
130
|
+
response = nil
|
131
|
+
|
132
|
+
begin
|
133
|
+
puts "Request to " + host + entity
|
134
|
+
Net::HTTP.start(host, 80) { |http|
|
135
|
+
response = http.get(entity)
|
136
|
+
}
|
137
|
+
|
138
|
+
rescue => e
|
139
|
+
puts e
|
140
|
+
rescue Timeout::Error => e
|
141
|
+
timeOut
|
137
142
|
|
138
|
-
rescue => e
|
139
|
-
puts e
|
140
|
-
rescue Timeout::Error => e
|
141
|
-
timeOut
|
142
|
-
|
143
|
-
else
|
144
|
-
res = case response
|
145
|
-
when Net::HTTPSuccess
|
146
|
-
reviewRes( response.body.force_encoding("UTF-8") )
|
147
|
-
# return response.body.force_encoding("UTF-8")
|
148
|
-
# when Net::HTTPRedirection
|
149
|
-
# fetch(response['location'], limit - 1)
|
150
|
-
when Net::HTTPForbidden
|
151
|
-
forbidden
|
152
|
-
when Net::HTTPNotFound
|
153
|
-
notFound
|
154
|
-
when Net::HTTPServiceUnavailable
|
155
|
-
serviceUnavailable
|
156
143
|
else
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
144
|
+
res = case response
|
145
|
+
when Net::HTTPSuccess
|
146
|
+
reviewRes( response.body.force_encoding("UTF-8") )
|
147
|
+
# return response.body.force_encoding("UTF-8")
|
148
|
+
# when Net::HTTPRedirection
|
149
|
+
# fetch(response['location'], limit - 1)
|
150
|
+
when Net::HTTPForbidden
|
151
|
+
forbidden
|
152
|
+
when Net::HTTPNotFound
|
153
|
+
notFound
|
154
|
+
when Net::HTTPServiceUnavailable
|
155
|
+
serviceUnavailable
|
156
|
+
else
|
157
|
+
unknownError
|
158
|
+
end
|
159
|
+
end until res["order"] == "success" ||
|
160
|
+
res["order"] == "terminate"
|
161
161
|
|
162
|
-
|
162
|
+
res
|
163
|
+
end
|
163
164
|
end
|
164
|
-
end
|
165
165
|
|
166
|
-
class
|
167
|
-
|
166
|
+
class MylistAtom < Xml
|
167
|
+
private
|
168
168
|
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
169
|
+
def forbidden
|
170
|
+
# マイリストが非公開の場合、html/Atomのどちらへのリクエストであっても、403が返ってくる。
|
171
|
+
notPublic
|
172
|
+
end
|
173
173
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
174
|
+
def reviewRes(resBody)
|
175
|
+
if # アクセス集中時
|
176
|
+
/大変ご迷惑をおかけいたしますが、しばらく時間をあけてから再度検索いただくようご協力をお願いいたします。/ =~
|
177
|
+
resBody.force_encoding("UTF-8")
|
178
|
+
then
|
179
|
+
serverIsBusy
|
180
|
+
else
|
181
|
+
success(resBody)
|
182
|
+
end
|
183
|
+
end
|
183
184
|
end
|
184
|
-
end
|
185
185
|
|
186
|
-
class
|
187
|
-
|
186
|
+
class TagAtom < Xml
|
187
|
+
private
|
188
188
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
189
|
+
def forbidden
|
190
|
+
# マイリストが非公開の場合、html/Atomのどちらへのリクエストであっても、403が返ってくる。
|
191
|
+
notPublic
|
192
|
+
end
|
193
193
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
194
|
+
def reviewRes(resBody)
|
195
|
+
if # アクセス集中時
|
196
|
+
/大変ご迷惑をおかけいたしますが、しばらく時間をあけてから再度検索いただくようご協力をお願いいたします。/ =~
|
197
|
+
resBody.force_encoding("UTF-8")
|
198
|
+
then
|
199
|
+
serverIsBusy
|
200
|
+
else
|
201
|
+
success(resBody)
|
202
|
+
end
|
203
|
+
end
|
203
204
|
end
|
204
|
-
end
|
205
205
|
|
206
|
-
class
|
207
|
-
|
206
|
+
class GetThumbInfo < Xml
|
207
|
+
private
|
208
208
|
|
209
|
-
|
210
|
-
|
209
|
+
def reviewRes(resBody)
|
210
|
+
r = resBody.force_encoding("UTF-8")
|
211
211
|
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
212
|
+
if # getThumbInfoは、該当する動画がない・削除済み・コミュニティ限定でも200が返ってくる。
|
213
|
+
/<nicovideo_thumb_response\sstatus=\"fail\">/ =~ r
|
214
|
+
if /<code>NOT_FOUND<\/code>/ =~ r
|
215
|
+
notFound
|
216
|
+
elsif /<code>DELETED<\/code>/ =~ r
|
217
|
+
deleted
|
218
|
+
elsif /<code>COMMUNITY<\/code>/ =~ r
|
219
|
+
limInCommunity
|
220
|
+
else
|
221
|
+
serverIsBusy
|
222
|
+
end
|
220
223
|
else
|
221
|
-
|
222
|
-
end
|
223
|
-
|
224
|
-
success(resBody)
|
225
|
-
end
|
224
|
+
success(resBody)
|
225
|
+
end
|
226
|
+
end
|
226
227
|
end
|
227
|
-
end
|
228
228
|
|
229
|
-
class HtmlConnector < Connector
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
@mech = Mechanize.new
|
255
|
-
# メモリ節約のため、Mechanizeの履歴機能を切る。
|
256
|
-
@mech.max_history = 1
|
229
|
+
class HtmlConnector < Connector
|
230
|
+
def initialize(mode)
|
231
|
+
@mode = mode
|
232
|
+
# デフォルトのウェイト設定
|
233
|
+
@waitConfig = {
|
234
|
+
'consec_count' => 10, # 連続してリクエストする回数
|
235
|
+
'consec_wait' => 10, # 連続リクエスト後のウェイト
|
236
|
+
'each' => 10, # 連続リクエスト時の、1リクエスト毎のウェイト
|
237
|
+
|
238
|
+
'200-abnormal' => 300, # アクセス拒絶時(「短時間での連続アクセスは・・・」)の場合の再試行までの時間
|
239
|
+
'unavailable' => 10,
|
240
|
+
'403' => 300, # "403"時の再試行までのウェイト
|
241
|
+
'404' => 300, # "403"時の再試行までのウェイト
|
242
|
+
'increment' => 1, # アクセス拒絶時の、次回以降の1リクエスト毎のウェイトの増加量
|
243
|
+
|
244
|
+
'timeout' => 10, # タイムアウト時の、再試行までのウェイト
|
245
|
+
'500' => 10, # "500"時の再試行までのウェイト
|
246
|
+
'503' => 10, # "503"時の再試行までのウェイト
|
247
|
+
|
248
|
+
'retryLimit' => 3 # 再試行回数の限度
|
249
|
+
}
|
250
|
+
|
251
|
+
# 1つの検索結果画面に表示される動画の数。現時点では32個がデフォルトの模様。
|
252
|
+
@NumOfSearched = 32
|
257
253
|
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
public
|
262
|
-
|
263
|
-
def errorStatus(ex)
|
264
|
-
# 再試行回数が
|
265
|
-
@retryTime += 1
|
266
|
-
if @retryTime >= @wait['allowance_time']
|
267
|
-
return false
|
268
|
-
end
|
254
|
+
@mech = Mechanize.new
|
255
|
+
# メモリ節約のため、Mechanizeの履歴機能を切る。
|
256
|
+
@mech.max_history = 1
|
269
257
|
|
270
|
-
|
271
|
-
when '403' then
|
272
|
-
sleep @wait['403']
|
273
|
-
warn "403"
|
274
|
-
when '500' then
|
275
|
-
sleep @wait['500']
|
276
|
-
warn "500"
|
277
|
-
when '503' then
|
278
|
-
sleep @wait['503']
|
279
|
-
warn "503"
|
280
|
-
else
|
281
|
-
warn "Server error: #{ex.code}"
|
282
|
-
return false
|
258
|
+
@consec_count = 0
|
283
259
|
end
|
284
|
-
|
285
|
-
|
286
|
-
@failed += 1
|
287
|
-
end
|
260
|
+
|
261
|
+
public
|
288
262
|
|
289
|
-
|
290
|
-
|
263
|
+
def errorStatus(ex)
|
264
|
+
# 再試行回数が
|
265
|
+
@retryTime += 1
|
266
|
+
if @retryTime >= @wait['allowance_time']
|
267
|
+
return false
|
268
|
+
end
|
291
269
|
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
rescue Mechanize::ResponseCodeError => ex
|
306
|
-
if errorStatus(ex) then retry
|
307
|
-
else break end
|
308
|
-
|
309
|
-
# HTTP Status:200時の処理
|
310
|
-
else
|
311
|
-
procedure.call
|
312
|
-
|
313
|
-
# 失敗カウントが指定回数を超えたらループを終わる。
|
314
|
-
if @failed >= @wait['allowance_time'] then
|
315
|
-
puts 'Exceeded the limit of retry time.'
|
316
|
-
@connection = false
|
317
|
-
break
|
270
|
+
case ex.response_code
|
271
|
+
when '403' then
|
272
|
+
sleep @wait['403']
|
273
|
+
warn "403"
|
274
|
+
when '500' then
|
275
|
+
sleep @wait['500']
|
276
|
+
warn "500"
|
277
|
+
when '503' then
|
278
|
+
sleep @wait['503']
|
279
|
+
warn "503"
|
280
|
+
else
|
281
|
+
warn "Server error: #{ex.code}"
|
282
|
+
return false
|
318
283
|
end
|
319
|
-
|
284
|
+
|
285
|
+
@connection = false
|
286
|
+
@failed += 1
|
287
|
+
end
|
320
288
|
|
321
|
-
|
322
|
-
|
323
|
-
# 成功 = true / 失敗 = false
|
324
|
-
return @connection
|
325
|
-
end
|
289
|
+
def htmlReq (url, request, procedure)
|
290
|
+
@failed = 0
|
326
291
|
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
292
|
+
# 再試行ループ
|
293
|
+
begin
|
294
|
+
eachWait
|
295
|
+
@connection = nil
|
296
|
+
request.call(url)
|
297
|
+
|
298
|
+
# タイムアウト時処理
|
299
|
+
rescue TimeoutError
|
300
|
+
timeOut
|
301
|
+
retry
|
302
|
+
|
303
|
+
# Mechanizeでアクセスし、200以外のステータスが返ってきた時
|
304
|
+
# 実際に該当するコードが返ってきたことがないので、正常に動くか不明
|
305
|
+
rescue Mechanize::ResponseCodeError => ex
|
306
|
+
if errorStatus(ex) then retry
|
307
|
+
else break end
|
308
|
+
|
309
|
+
# HTTP Status:200時の処理
|
310
|
+
else
|
311
|
+
procedure.call
|
312
|
+
|
313
|
+
# 失敗カウントが指定回数を超えたらループを終わる。
|
314
|
+
if @failed >= @wait['allowance_time'] then
|
315
|
+
puts 'Exceeded the limit of retry time.'
|
342
316
|
@connection = false
|
343
|
-
|
344
|
-
|
345
|
-
# ウェイトを置いた後、今後のページ毎のウェイトを増やす。
|
346
|
-
puts 'Waiting for ' + @wait['rejected'] + 's.'
|
347
|
-
sleep @wait['rejected']
|
348
|
-
@wait['each'] += @wait['increment']
|
349
|
-
puts 'Increased each @wait by ' + @wait['increment'] + 'sec.'
|
350
|
-
else
|
351
|
-
@connection = true
|
317
|
+
break
|
352
318
|
end
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
319
|
+
end until @connection
|
320
|
+
|
321
|
+
# 連続アクセスカウント+1
|
322
|
+
@consec_count += 1
|
323
|
+
# 成功 = true / 失敗 = false
|
324
|
+
return @connection
|
325
|
+
end
|
358
326
|
|
359
|
-
|
327
|
+
def htmlGet (host, entity)
|
328
|
+
htmlReq(
|
329
|
+
host + entity,
|
330
|
+
lambda { |url|
|
331
|
+
t = Thread.new do
|
332
|
+
@mech.get(url)
|
333
|
+
puts "Requesting for " + url
|
334
|
+
end
|
335
|
+
t.join
|
336
|
+
},
|
337
|
+
# HTTP Status:200時の処理
|
338
|
+
lambda {
|
339
|
+
# 連続アクセス拒絶メッセージが返ってきた時
|
340
|
+
if /短時間での連続アクセスはご遠慮ください/ =~ @mech.page.search('/html').text then
|
341
|
+
puts 'Access rejected.'
|
342
|
+
@connection = false
|
343
|
+
@failed += 1
|
344
|
+
|
345
|
+
# ウェイトを置いた後、今後のページ毎のウェイトを増やす。
|
346
|
+
puts 'Waiting for ' + @wait['rejected'] + 's.'
|
347
|
+
sleep @wait['rejected']
|
348
|
+
@wait['each'] += @wait['increment']
|
349
|
+
puts 'Increased each @wait by ' + @wait['increment'] + 'sec.'
|
350
|
+
else
|
351
|
+
@connection = true
|
352
|
+
end
|
353
|
+
}
|
354
|
+
)
|
355
|
+
|
356
|
+
return @mech.page
|
357
|
+
end
|
358
|
+
|
359
|
+
attr_reader :mech
|
360
|
+
end
|
360
361
|
end
|