以下はrubydocからの転載です。詳細はこちらを御覧下さい。

NicoScraper

My site: http://hdemon.net
GitHub: http://github.com/hdemon/nicoscraper/
Author: Masami Yonehara
Copyright: 2011
License: MIT License
Latest Version: 0.2.5
Release Date: Sep 24th 2011

何をするライブラリ?

 ニコニコ動画の動画ページ、検索ページ、あるいはそのAtomフィードから情報を取得し、その情報に対して各種操作を行えます。タグやマイリスト検索結果からの抽出、および抽出結果に対する反復処理を行うメソッドも備え、ランキングサイト等の制作を支援します。

インストール

 Ruby 1.9.2において動作を確認しています。インストールには、

$ gem install nicoscraper

 とした後、

require 'nicoscraper' 

 で使い始めて下さい。内部的にlibxml-rubyを使っており、インストール時に最新版に更新される可能性があります。

 なお、実行前に注意点、および免責事項をお読み下さい。

基本的な使い方

 Movieクラス、Mylistクラス、Searcherモジュールから主要な機能が構成されています。基本的には、動画やマイリストのIDを指定してインスタンスを作り、そこから詳細な情報を取得するためのメソッドを実行したのち、さらに分析や加工を行う別のメソッドを実行する、という手順を踏みます。

動画情報の取得

 例えばsm1097445という動画IDから、タイトルや動画の長さ、現在の閲覧数等の詳細な情報を知りたいときは、

require 'nicoscraper'

movie = Nicos::Movie::new("sm1097445")
movie.getInfo

p movie

 Movieクラスのインスタンス(以下「動画インスタンス」)を動画IDを与えて生成した後、getInfoメソッドを利用します。その結果、

<Nicos::Movie:0x00000002537aa8
  @video_id="sm1097445", 
  @available=false, 
  @title="【初音ミク】みくみくにしてあげる♪【してやんよ】", 
  @description="おまえら、みっくみくにしてやんよ。歌詞は...", 
  @thumbnail_url="http://tn-skr2.smile...", 
  @first_retrieve=1190218922, 
  @length=99, 
  @movie_type="flv", 
  @size_high=3906547, 
  @size_low=1688098, 
  @view_counter=9073614, 
  @comment_num=2553366, 
  @mylist_counter=183470, 
  @last_res_body="★███████████☆...", 
  @watch_url="http://www.nicovideo.jp/...", 
  @thumb_type="video", 
  @embeddable=1, 
  @no_live_play=0, 
  @tags_jp=["音楽", "初音ミク", ...], 
  @tags_tw=["彈幕強大", "把你MikuMiku掉♪", ...], 
  @user_id=70391 >

 このように、動画インスタンスにインスタンス変数として各種情報が付加されます。

マイリスト情報の取得

 Mylistクラスもほぼ同様ですが、Mylistクラスのインスタンス(以下「マイリストインスタンス」)は、マイリスト情報の他に、そのマイリストが含む動画のインスタンスを自動的に生成します。つまり、

require 'nicoscraper'

mylist = Nicos::Mylist::new("")
mylist.getInfoLt

p mylist

このように実行すると、

<Nicos::Mylist:0x00000002884670
  @mylist_id=15196568,
  @movies=[
    #<Nicos::Movie:0x0000000255a968
      @video_id="sm8481759", 
      @available=true, 
      @title="【Oblivion】おっさんの大冒険1(ゆっくり実況)",
      ...
    #<Nicos::Movie:0x0000000251a6b0 
      @video_id="sm8506034",
      @available=true,
      @title="【Oblivion】おっさんの大冒険2(ゆっくり実況)",
      ...
  ],
  @available=true,
  @title="【Oblivion】おっさんの大冒険", 
  ... >

 というように、動画インスタンスを勝手につくりだして配列として保持します。もちろん、これらの動画インスタンスには独立した操作を加えられます。

検索結果の取得

 タグやマイリスト検索結果からの情報取得には、Searcherモジュールを使います。情報のソート方法の指定、取得する範囲の制限が可能です。

require 'nicoscraper'

t = Time.now
ytd = Date::new(t.year, t.month, t.day) - 1
yesterday = Time.local(ytd.year, ytd.month, ytd.day, 0, 0, 0).to_i

searcher = Nicos::Searcher::ByTag.new()

searcher.execute('ゆっくり実況プレイpart1リンク', 'post_new', nil) {
  |result, page|

  result.each { |movieObj|
    puts movieObj.title +
      " is posted at " +
       Time.at(movieObj.first_retrieve).to_s

    "continue" if movieObj.first_retrieve >= yesterday 
  }  
}

 この例では、ゆっくり実況プレイpart1リンクというタグの付く動画を、post_new=投稿日時が新しい順からさかのぼって取得し、取得した動画の日付が前日の0時0分を超えるまでそれを続けます。

 ブロック内の第1引数には取得結果に基づく動画インスタンスが与えられるのですが、これは32個分の配列です。なぜ32個のセットなのかと言うと、ご存知のようにニコニコ動画の検索画面はページで区切られており、Searcherモジュールの各メソッドはページ毎に情報を取得し、ページ単位でブロックをコールするからです。HTMLから取得するにしろAtomフィードから取得するにしろ、1ページに32個の動画情報が含まれています。そして、第2引数には現在のページ数が与えられます。

 そして、ブロック内でcontinueの文字列を返すことによりスクレイプが継続します。つまり、continue文字列を返し続けるロジックを組み込まないと、1ページ目を読んだ時点で処理が終了します。これは意図せざる過剰アクセスを防ぐための措置です。

 上の例では、取得した動画の日付を調べ、3日前の0時0分より前の動画に到達すればそこでループを終える設計です。ループを継続するために取得情報を使うかどうかは任意なので、例えば10分間の制限で取得出来るだけ取得するということも可能でしょう。

取得した情報に対する操作

 現在のところ、以下のような操作が可能です。詳しい使い方は、各メソッドの説明を参照して下さい。

動画の説明文からタイトルを取得する。 Nicos::Movie::extrMylist

 動画の説明文中に、mylist/...という表記で投稿者がマイリストを提示している事があります。extrMylistはこれを全て取得し、配列として返します。

指定したマイリストに、自分自身が入っているかを調べる。 Nicos::Movie::isBelongsTo

そのマイリスト内に含まれる全ての動画の、タイトルの類似性を調べる。 Nicos::Mylist::getSimilarity

 マイリストのシリーズ性を判定するために、マイリスト内の全ての動画の組み合わせで、タイトルの「編集距離」に基づく類似度を計算します。

その動画が属する、シリーズとみなせるマイリストのIDを返します。 Nicos::Movie::isSeriesOf

 isBelongsTogetSimilarityの組み合わせにより、ある動画の説明文中にマイリストの記載がある場合、そのマイリストがタイトルの類似性によるシリーズとみなせるならば、そのIDを返します。

ウェイト設定について

ウェイトの役割

 Searcherメソッドは継続的なアクセスを行い、またそれ以外のメソッドも実際の運用目的上ある程度の連続使用が前提になると思います。このライブラリは並列的なリクエストを行いませんが、それでも過剰なアクセスに伴うサーバからの拒絶や、あるいはそれ以上に、アカウントの停止もしくは法的責任を追求されるなどの事があり得ないという保証はできません。

 それを防ぐための措置の一つが、continueを明示的に返さないとスクレイピングが継続しない仕様ですが、もう一つ、アクセス中のウェイトを任意に設定できるようにしています。具体的には、連続リクエストの上限回数、連続リクエスト後のウェイト、1リクエスト毎のウェイト、連続アクセス拒絶時やサーバ混雑時の再試行までのウェイトなどです。ウェイトの設定は、以下のようにNicos::Connector::Config::waitConfigに与えられています。以下はデフォルトの設定です。

Nicos::Connector::Config::waitConfig = {

  # module::Searcher用の設定
  'seqAccLimit' => 10,  # 連続してリクエストする回数
  'afterSeq'    => 10,  # 連続リクエスト後のウェイト(以下全て単位は秒)
  'each'        => 5,   # 連続リクエスト時の、1リクエスト毎のウェイト

  # 全メソッド共通の設定
  'deniedSeqReq'=> {    # 連続アクセス拒絶時
    'retryLimit'  => 3,   # 再試行回数の上限
    'wait'        => 120  # 再試行までのウェイト
  },

  'serverIsBusy'=> {    # サーバ混雑時
    'retryLimit'  => 3,
    'wait'        => 120
  },

  'serviceUnavailable' => { # 503時
    'retryLimit'  => 3,
    'wait'        => 120
  },

  'timedOut' => {       # タイムアウト時
    'retryLimit'  => 3,
    'wait'        => 10
  },

  'increment'   => 1    # 異常ステータス時の、次回以降の1リクエスト毎のウェイトの増加量
}

連続リクエストとは?

   Searcherメソッドはある一定回数のHTTPリクエストを1つの単位とし、その単位のリクエストが終わるごとに休憩を入れます。この1単位を連続リクエストと言います。上の例では、10のリクエストを1単位とし(seqAccLimit)、その連続リクエストが終わった後に10秒の休憩を入れる(afterSeq)設定になっています。

 なお、連続リクエスト毎に限らず、1リクエスト毎のウェイトも併せて設定できます。上の例では、1リクエスト毎に1秒のウェイトを入れる設定です(each)。

レスポンスの種類に対する反応について

 ニコニコ動画のサーバのレスポンスには、正常にデータを返す以外にいくつかの反応があります。この反応に応じて再試行するか、それともそのリクエストをパスするかが決定されます。以下はレスポンスの内容と、それに対応するウェイト設定用ハッシュのキーです。

1. 404、削除済み

 これらの場合、何も情報を取得せずに終えます。

2. 連続アクセスの拒絶 :deniedSeqReq

 "短時間での連続アクセスはご遠慮ください" と表示される場合です。設定に従って再試行します。

3. サーバ混雑時 :serverIsBusy

 "大変ご迷惑をおかけいたしますが、しばらく時間をあけてから再度検索いただくようご協力をお願いいたします。" と表示される場合です。再試行します。

4. 非公開・権限なし

 動画がマイリストが非公開設定されている場合、あるいはコミュニティ未加入者には非公開になっている動画があります。後者についてはログイン処理を事前に行うことで技術的には取得可能ですが、v 0.2では未実装です。これらの動画の場合、取得をパスします。なお、この場合は403が返っています。

5. 503 :serviceUnavailable

 メンテナンス時に限らず、稼働時にも稀に発生します。処理全体を中断することはなく、再試行を行います。

6. タイムアウト :timedOut

 再試行します。

 2、3、5に該当した場合には、incrementを指定することで、次回以降の1リクエスト毎のウェイトを増加させることができます。

設定方法

 ウェイトは、全メソッドが共有する設定と、各インスタンスのみに有効な設定の2つを定義できます。

 また、全メソッドの共有設定には初期設定があり、それが上に挙げたハッシュです。これを変更するには、Nicos::Connector::Config::setWait`メソッドを利用します。これにより、その後に生成した各インスタンスにおいて、変更した設定が共有されます。

 もう1つの方法は、動画・マイリスト・Searcherモジュール下クラスの特異メソッドとしての`setWait'メソッドを使う方法です。この方法では、そのインスタンスにおいてのみ変更が有効になります。

 なお、setWaitメソッドは指定したキーの部分のみを上書きするため、設定毎に上記の書式のハッシュオブジェクトを用意する必要はありません。

wait = {
  'seqAccLimit' => 100,

  'deniedSeqReq'=> {   
    'wait'        => 1200  
  }
}

Nicos::Connector::Config::setWait(wait)

 例えばこのようにすることで、次回以降のseqAccLimitdeniedSeqReq -> waitのみが前回の設定に上書きされます。

注意点、および免責事項

 繰り返しになりますが、それぞれのメソッドは大半がニコニコ動画へのアクセスを伴い、特にSearcherモジュールは継続的かつ無制限なアクセスを可能にするため、使用方法によっては開発者である私が通常の使用において想定していない負荷を、ニコニコ動画に対して与える可能性があります。

 その結果、アカウントの停止や法的な責任を追求される可能性も無いとは言えません。その点を考慮し、上で述べた幾つかの制限を行なっています。特にウェイトは大きめに設定してあります。

 このウェイトは、ご自分の責任において変更して下さい。本ライブラリの使用によって発生した損害および法的な責任については、開発者が現在認識していない、あるいはそのバージョンの公開時には認識していなかったバグに起因するものを含め、一切の責任を負いかねます。またこのような事情から、予告なく公開を停止する可能性があります。

 なお、HTMLからスクレイプするメソッドよりも、Atomフィードを使うメソッドの方がニコニコ動画側の負荷が(たぶん)軽く、アクセス制限などは経験上起こりにくくなっています。HTMLメソッドを利用した場合、混雑時には結構な頻度で連続アクセスが拒絶されます。大半の情報はAtomフィードで取得できるため、そうでない情報を取得したい場合に限り、HTMLを利用するメソッドを使うべきでしょう。

その他

文中の用語・用法

動画インスタンス Movieクラスのインスタンス

マイリストインスタンス Mylistクラスのインスタンス

動画ID | video_id ニコニコ動画の各動画に与えられる、sm|nmで始まる一意のID。

アイテムID | item_id 動画に与えられるもう一つの一意なIDであり、投稿日時と同じか非常に近いUNIX時間になっている。例えば、"【初音ミク】みくみくにしてあげる♪【してやんよ】"の動画IDはsm1097445であり、アイテムIDは1190218917である。このアイテムIDを日時に直すと、日本時間における2007年9月20日 1:21:57となるが、動画に投稿日時として表示されるのは、2007年9月20日 1:22:02である。

更新履歴

v 0.2.6

  • ドキュメントが正しく生成されていなかったので訂正。

v 0.2.5

  • ヘッダの追加

  • コードと設定の分離

v 0.2.4

  • ドキュメント作成

  • Searcherループのバグ修正。

  • Searcherループの継続判定を、ブロック内で"continue"を返す事を要求する方式に変更。

今後の予定

v 0.3

  • HTMLから取得・解析するメソッドの追加。

  • キーワード検索の実装

v 0.4-

  • シリーズ性判定の強化。説明文中にある「次 sm***」等の表記を解析し、マイリストに頼らずにシリーズ性を判定するようにする。

  • コミュニティ動画、限定公開動画・マイリストへの対応。

要望、バグ報告について

以下のどちらかにお願いします。

GitHubを経由して下さってもいいのですが、まだ慣れていないので対応が送れるかもしれません。