nicoscraper 0.2.9 → 0.2.10

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 CHANGED
@@ -9,8 +9,8 @@ NicoScraper
9
9
  **Author:** Masami Yonehara
10
10
  **Copyright:** 2011
11
11
  **License:** MIT License
12
- **Latest Version:** 0.2.7
13
- **Release Date:** Sep 25th 2011
12
+ **Latest Version:** 0.2.10
13
+ **Release Date:** Sep 30th 2011
14
14
 
15
15
 
16
16
  何をするライブラリ?
@@ -130,7 +130,7 @@ NicoScraper
130
130
  searchByTag = Nicos::Searcher::ByTag.new()
131
131
  searchByTag.execute(
132
132
  'VOCALOID',
133
- 'post_new'
133
+ :post_new
134
134
  ) { |result, status|
135
135
  terminate = false
136
136
 
@@ -194,34 +194,31 @@ NicoScraper
194
194
   それを防ぐための措置の一つが、`"continue"`を明示的に返さないとスクレイピングが継続しない仕様ですが、もう一つ、アクセス中のウェイトを任意に設定できるようにしています。具体的には、連続リクエストの上限回数、連続リクエスト後のウェイト、1リクエスト毎のウェイト、連続アクセス拒絶時やサーバ混雑時の再試行までのウェイトなどです。ウェイトの設定は、以下のように`Nicos::Connector::Config::waitConfig`に与えられています。以下はデフォルトの設定です。
195
195
 
196
196
  Nicos::Connector::Config::waitConfig = {
197
+ :seqAccLimit => 10, # 連続してリクエストする回数
198
+ :afterSeq => 10, # 連続リクエスト後のウェイト(以下全て単位は秒)
199
+ :each => 1, # 連続リクエスト時の、1リクエスト毎のウェイト
197
200
 
198
- # module::Searcher用の設定
199
- 'seqAccLimit' => 10, # 連続してリクエストする回数
200
- 'afterSeq' => 10, # 連続リクエスト後のウェイト(以下全て単位は秒)
201
- 'each' => 5, # 連続リクエスト時の、1リクエスト毎のウェイト
201
+ :increment => 1, # 例外発生時の、次回以降の1リクエスト毎のウェイトの増加量
202
202
 
203
- # 全メソッド共通の設定
204
- 'deniedSeqReq'=> { # 連続アクセス拒絶時
205
- 'retryLimit' => 3, # 再試行回数の上限
206
- 'wait' => 120 # 再試行までのウェイト
203
+ :deniedSeqReq=> { # 連続アクセス拒絶時
204
+ :retryLimit => 3, # 再試行回数の上限
205
+ :wait => 120 # 再試行までのウェイト
207
206
  },
208
207
 
209
- 'serverIsBusy'=> { # サーバ混雑時
210
- 'retryLimit' => 3,
211
- 'wait' => 120
208
+ :serverIsBusy=> { # サーバ混雑時
209
+ :retryLimit => 3,
210
+ :wait => 120
212
211
  },
213
212
 
214
- 'serviceUnavailable' => { # 503時
215
- 'retryLimit' => 3,
216
- 'wait' => 120
213
+ :serviceUnavailable => { # 503時
214
+ :retryLimit => 3,
215
+ :wait => 120
217
216
  },
218
217
 
219
- 'timedOut' => { # タイムアウト時
220
- 'retryLimit' => 3,
221
- 'wait' => 10
222
- },
223
-
224
- 'increment' => 1 # 異常ステータス時の、次回以降の1リクエスト毎のウェイトの増加量
218
+ :timedOut => { # タイムアウト時
219
+ :retryLimit => 3,
220
+ :wait => 10
221
+ }
225
222
  }
226
223
 
227
224
  ###連続リクエストとは?
@@ -271,10 +268,10 @@ NicoScraper
271
268
   なお、setWaitメソッドは指定したキーの部分のみを上書きするため、設定毎に上記の書式のハッシュオブジェクトを用意する必要はありません。
272
269
 
273
270
  wait = {
274
- 'seqAccLimit' => 100,
271
+ :seqAccLimit => 100,
275
272
 
276
- 'deniedSeqReq'=> {
277
- 'wait' => 1200
273
+ :deniedSeqReq => {
274
+ :wait => 1200
278
275
  }
279
276
  }
280
277
 
@@ -323,9 +320,32 @@ Mylistクラスのインスタンス
323
320
  GitHubを経由して下さってもいいのですが、まだ慣れていないので対応が遅れるかもしれません。
324
321
 
325
322
 
323
+ ###今後の予定
324
+
325
+ **v 0.3**
326
+
327
+ + HTMLから取得・解析するメソッドの追加。
328
+
329
+ + キーワード検索の実装。
330
+
331
+ **v 0.4-**
332
+
333
+ + シリーズ性判定の強化。説明文中にある「次 sm***」等の表記を解析し、マイリストに頼らずにシリーズ性を判定するようにする。
334
+
335
+ + コミュニティ動画、限定公開動画・マイリストへの対応。
336
+
337
+
326
338
  ###更新履歴
327
339
 
328
- **v 0.2.8 - 0.2.9**
340
+ **v 0.2.10**
341
+
342
+ + 例外発生時に終了してしまうバグを修正。
343
+
344
+ + リクエスト成否等のステータスの詳細化。
345
+
346
+ + パラメータの文字列による指定からシンボルによる指定への変更。
347
+
348
+ **v 0.2.8 0.2.9**
329
349
 
330
350
  + MylistAtomパーサが再生数等を認識しない問題を修正。
331
351
 
@@ -355,17 +375,3 @@ GitHubを経由して下さってもいいのですが、まだ慣れていな
355
375
 
356
376
  + Searcherループの継続判定を、ブロック内で`"continue"`を返す事を要求する方式に変更。
357
377
 
358
-
359
- ###今後の予定
360
-
361
- **v 0.3**
362
-
363
- + HTMLから取得・解析するメソッドの追加。
364
-
365
- + キーワード検索の実装。
366
-
367
- **v 0.4-**
368
-
369
- + シリーズ性判定の強化。説明文中にある「次 sm***」等の表記を解析し、マイリストに頼らずにシリーズ性を判定するようにする。
370
-
371
- + コミュニティ動画、限定公開動画・マイリストへの対応。
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.9
1
+ 0.2.10
@@ -6,16 +6,87 @@ require 'net/http'
6
6
 
7
7
  module Nicos
8
8
  module Connector
9
+
10
+ #
11
+ #
12
+ #
13
+ #==ブロック内の第2引数について
14
+ #
15
+ # 第2引数には、それまでの検索の成否、例外の発生回数などを記録した
16
+ # ハッシュが渡されます。これは以下のような構造になっています。
17
+ #
18
+ # {
19
+ # # 各種例外等が発生した動画・マイリストのIDを配列で保管。
20
+ # "allDisabled" => [],
21
+ # "notPublic" => [],
22
+ # "limInCommunity" => [],
23
+ # "notFound" => [],
24
+ # "deleted" => [],
25
+ #
26
+ # # 再試行で対処できる例外等が発生した件数。
27
+ # "deniedSeqReq" => 0,
28
+ # "serverIsBusy" => 0,
29
+ # "serviceUnavailable" => 0,
30
+ # "timedOut" => 0,
31
+ #
32
+ # # 成功回数
33
+ # "succeededNum" => 0
34
+ # }
35
+ #
36
+ # これらのパラメータが複数の結果を保持する前提になっているのは、Searcherモジュール
37
+ # に対応させる為です。将来的には、Movie/Mylistクラス
38
+ # には専用のハッシュを設ける設計にするつもりです。
39
+ #
40
+ # **allDisabled**
41
+ #  マイリストの場合のみ機能。そのマイリスト内の動画が全て非公開、
42
+ # あるいは削除済み等で存在しないが、マイリストは残っている場合。
43
+ #
44
+ # **notPublic**
45
+ #  動画、マイリストが非公開である場合。
46
+ #
47
+ # **limInCommunity**
48
+ #  動画、マイリストがコミュニティ限定公開である場合。
49
+ #
50
+ # **notFound**
51
+ #  動画、マイリストが存在しない場合。マイリストは削除済みの場合もnotFoundとなる。
52
+ #
53
+ # **deleted**
54
+ #  その動画が削除済みである場合。マイリストについては、上のnotFoundと
55
+ # 区別されない。
56
+ #
57
+ # **deniedSeqReq**
58
+ #  連続アクセスとして明示的に拒否された場合。
59
+ #
60
+ # **serverIsBusy**
61
+ #  「大変ご迷惑をおかけいたしますが、しばらく時間をあけてから
62
+ # 再度検索いただくようご協力をお願いいたします。」と表示される場合。
63
+ #
64
+ # **serviceUnavailable**
65
+ #  503が返ってきた時。
66
+ #
67
+ # **timedOut**
68
+ #  タイムアウト
69
+ #
70
+ # **succeededNum**
9
71
  class Connector < Config
72
+ include Nicos::Connector::SetWait
73
+
10
74
  def initialize
11
75
  # デフォルトのウェイト設定
12
76
  @seqTime = 0
13
77
  @result = {
14
- "notPublic" => [],
15
- "limInCommunity" => [],
16
- "notFound" => [],
17
- "deleted" => [],
18
- "succeededNum" => 0
78
+ :allDisabled => [],
79
+ :notPublic => [],
80
+ :limInCommunity => [],
81
+ :notFound => [],
82
+ :deleted => [],
83
+
84
+ :deniedSeqReq => 0,
85
+ :serverIsBusy => 0,
86
+ :serviceUnavailable => 0,
87
+ :timedOut => 0,
88
+
89
+ :succeededNum => 0
19
90
  }
20
91
  @waitConfig = @@waitConfig
21
92
  end
@@ -23,102 +94,148 @@ module Nicos
23
94
  attr_accessor :result
24
95
 
25
96
  private
97
+
98
+ # 再試行しない例外の共通処理
99
+ def accessDisabled(exception)
100
+ @result[exception].push(@nowAccess)
101
+ { :order => :skip, :status => exception }
102
+ end
103
+
104
+ def allDisabled
105
+ # MylistAtomについて、全ての動画が非公開あるいはその他の理由でRSSフィードに掲載されない時。
106
+ puts "All movies are disabled."
107
+ accessDisabled(:allDisabled)
108
+ end
26
109
 
27
110
  def notPublic
28
- # マイリスト非公開のときに403になる。後で専用の処理を入れるべき。
111
+ # マイリスト非公開のときに403になる。
112
+ # http://www.nicovideo.jp/mylist/25479830
29
113
  puts "This movie/mylist is not public."
30
- @result["notPublic"].push(@nowAccess)
31
- return { "order" => "skip" }
114
+ accessDisabled(:notPublic)
32
115
  end
33
116
 
34
117
  def limInCommunity
35
118
  puts "This movie/mylist is limited in comunity members."
36
119
  # ex. item_id -> 1294702905
37
- @result["limInCommunity"].push(@nowAccess)
38
- return { "order" => "skip" }
120
+ accessDisabled(:limInCommunity)
39
121
  end
40
122
 
41
123
  def notFound
42
124
  puts "This movie/mylist is not found."
43
- @result["notFound"].push(@nowAccess)
44
- return { "order" => "skip" }
125
+ accessDisabled(:notFound)
45
126
  end
46
127
 
47
- def deleted
128
+ def deleted # マイリストは削除と404の区別がない?
48
129
  puts "This movie/mylist is deleted."
49
- @result["deleted"].push(@nowAccess)
50
- return { "order" => "skip" }
130
+ accessDisabled(:deleted)
131
+ end
132
+
133
+ # 以下、再試行の可能性のある例外
134
+
135
+ # 共通処理
136
+ def exception(exception, retryCount)
137
+ if retryCount <= @waitConfig[exception][:retryLimit]
138
+ { :order => :skip }
139
+ else
140
+ sleep @waitConfig[exception][:wait]
141
+ @result[exception] += 1
142
+ { :order => :retry }
143
+ end
51
144
  end
52
145
 
53
- def deniedSeqReq
146
+ def deniedSeqReq(retryCount)
54
147
  puts "Denied sequential requests."
55
- sleep @waitConfig["deniedSeqReq"]
56
- @result = "deniedSeqReq"
57
- return { "order" => "retry" }
148
+ exception(:deniedSeqReq, retryCount)
58
149
  end
59
150
 
60
- def serverIsBusy
151
+ def serverIsBusy(retryCount)
61
152
  puts "The server is busy."
62
- sleep @waitConfig["serverIsBusy"]
63
- @result = "serverIsBusy"
64
- return { "order" => "retry" }
153
+ exception(:serverIsBusy, retryCount)
65
154
  end
66
155
 
67
- def serviceUnavailable
156
+ def serviceUnavailable(retryCount)
68
157
  puts "Service unavailable."
69
- sleep @waitConfig["serviceUnavailable"]
70
- @result = "serviceUnavailable"
71
- return { "order" => "retry" }
158
+ exception(:serviceUnavailable, retryCount)
72
159
  end
73
160
 
74
- def timedOut
161
+ def timedOut(retryCount)
75
162
  puts "Request timed out."
76
- sleep @waitConfig["timedOut"]
77
- @result = "timedOut"
78
- return { "order" => "retry" }
163
+ exception(:timedOut, retryCount)
79
164
  end
80
165
 
81
- def reachedLast
166
+
167
+ def reachedLast
168
+ # TagAtom専用。MylistAtomは、allDisabledと結果が被ってしまう。
82
169
  puts "Reached the last page."
83
- @result = "reachedLast"
84
- return { "order" => "terminate" }
170
+ { :order => :terminate }
85
171
  end
86
172
 
87
173
  def succeeded(resBody)
88
- @result["succeededNum"] += 1
89
- sleep @waitConfig["each"]
174
+ @result[:succeededNum] += 1
175
+ sleep @waitConfig[:each]
90
176
  @seqTime += 1
91
177
 
92
- if @seqTime >= @waitConfig["seqAccLimit"]
93
- sleep @waitConfig["afterSeq"]
178
+ if @seqTime >= @waitConfig[:seqAccLimit]
179
+ sleep @waitConfig[:afterSeq]
94
180
  @seqTime = 0
95
181
  end
96
- return { "order" => "afterTheSuccess", "body" => resBody }
182
+
183
+ {
184
+ :status => :success,
185
+ :order => :afterTheSuccess,
186
+ :body => resBody
187
+ }
97
188
  end
98
189
 
99
190
  def wait(status)
100
191
  puts "Wait for " + waitTime + " second."
101
192
  sleep @waitConfig[status.to_s]
102
193
  end
103
-
194
+
104
195
  public
196
+
197
+ # リクエスト結果を格納する変数を、MylistやMovie等の
198
+ # 単一リクエストメソッド用に構造を変換する。
199
+ def getStatus
200
+ status = {
201
+ :status => nil,
202
+ :retry => {}
203
+ }
204
+
205
+ @result.each_key do |key|
206
+ if @result[key].instance_of?(Array) && @result[key].length >= 1
207
+ status[:status] = key
208
+ elsif key === :succeededNum && @result[key] >= 1
209
+ status[:status] = :success
210
+ elsif @result[key].instance_of?(Fixnum)
211
+ status[:retry][key] = @result[key]
212
+ end
213
+ end
214
+
215
+ status
216
+ end
105
217
  end
106
218
 
107
219
  class Xml < Connector
108
220
  def get (host, entity)
109
221
  response = nil
222
+ retryCount = 0
223
+ res = {}
110
224
 
111
225
  begin
112
- puts "Request to " + host + entity
226
+ @nowAccess = host + entity
227
+ puts "Request to " + @nowAccess
113
228
  Net::HTTP.start(host, 80) { |http|
114
229
  response = http.get(entity, HEADER)
115
230
  }
116
- @nowAccess = host + entity
231
+ retryCount += 1
117
232
 
118
233
  rescue => e
119
234
  puts e
120
235
  rescue Timeout::Error => e
121
- timeOut
236
+ debugger
237
+ timeOut
238
+ res[:order] = :retry
122
239
 
123
240
  else
124
241
  res = case response
@@ -128,21 +245,22 @@ module Nicos
128
245
  # when Net::HTTPRedirection
129
246
  # fetch(response['location'], limit - 1)
130
247
  when Net::HTTPForbidden
131
- forbidden
248
+ forbidden
132
249
  when Net::HTTPNotFound
133
250
  notFound
134
251
  when Net::HTTPServiceUnavailable
252
+ debugger
135
253
  serviceUnavailable
136
254
  else
137
255
  unknownError
138
256
  end
139
- end until res["order"] != "retry"
257
+ end until res[:order] != :retry
140
258
 
141
259
  res
142
260
  end
143
261
  end
144
262
 
145
- class MylistAtom < Xml
263
+ class TagAtom < Xml
146
264
  private
147
265
 
148
266
  def forbidden
@@ -164,7 +282,19 @@ module Nicos
164
282
  end
165
283
  end
166
284
 
167
- class TagAtom < MylistAtom
285
+ class MylistAtom < TagAtom
286
+ def reviewRes(resBody)
287
+ resBody = resBody.force_encoding("UTF-8")
288
+ if # アクセス集中時
289
+ /大変ご迷惑をおかけいたしますが、しばらく時間をあけてから再度検索いただくようご協力をお願いいたします。/ =~
290
+ resBody then
291
+ serverIsBusy
292
+ elsif /\<entry\>/ =~ resBody && /\<\/entry\>/ =~ resBody
293
+ succeeded(resBody)
294
+ else
295
+ allDisabled
296
+ end
297
+ end
168
298
  end
169
299
 
170
300
  class GetThumbInfo < Xml