ニコニコ動画 タグ検索スクリプト

昨日に引き続き、nicovideo gemのサンプルを作成します。
尚、GEMのバージョンが0.1.1になっているので、忘れずにバージョンアップしましょう。id:emergentさん早速の修正ありがとう御座います。
本日は、タグ検索機能のサンプルです。

とりあえず動かす

"初音ミク"タグが付いた動画を取得します。取得件数はニコニコ動画の仕様上30件となっています。

#!/usr/bin/ruby -Ku
require 'rubygems'
require 'nicovideo'

conf = YAML.load(open("conf.yaml") )
nv = Nicovideo.new(conf['mail'], conf['password'])

nv.tagsearch("初音ミク").each do |vp|
  printf "%-12s %s \n", vp.video_id, vp.title
end

以下が出力。

sm2157734    妹を盗撮してたら見つかって襲いかかってきた!!
sm2437325    週刊VOCALOIDランキング #21
sm2380947    【初音ミク】Caramelldansen 全部ミク【ウッーウッーウマウマ(゚∀゚)】
sm2436833    不定期刊VOCALOIDランキング2部 #5
sm2352026    蠍−HumanBeatBox 5th stage
sm2434486    3D初音ミク・必殺技集(スト2)
sm2370613    週刊VOCALOIDランキング #20
sm2425074    【初音ミク】without you【オリジナル曲】
sm2437498    【双海亜美】 ポジティブ!〜VOC@LOID Edit〜 【初音ミク】
sm2428954    SUPER DEADBALL BEAT【初音ミク】
sm1234123    有名人になるであろう人の写真を集めた
sm2418429    【初音ミクオリジナル】 いのちのうた Another Mix 【手書きPV付】
sm2420025    3Dミクを躍らせるツールを自作してみた(説明前編)
sm2435965    ミク リン レンでオリジナル 「穏やかに日常」
sm2420128    3Dミクを躍らせるツールを自作してみた(説明後編)
sm2060339    【初音ミク】オリジナル曲「海の向こう」(No.003)【最終版】
sm2408076    【弱音ハク】SUPER YOWANE MEDLEY 0222
sm1097445    【初音ミク】みくみくにしてあげる♪【してやんよ】
sm1914676    【初音ミク】みくみくにしてあげる♪を大音量で再生してみた!
sm2242549    【初音ミク】たちが「いつも何度でも」を歌いました【習作】
sm2406770    初音ミク「桜ノ雨」オリジナル曲
sm2437921    MikuMikuDanceで初音ミクにうんこさせてみた
sm2425134    【初音ミク】コンビニPV(Short.ver)【オリジナル曲】
sm2435563    【初音ミク・鏡音リン・レン】暗い森のサーカス【不気味ワルツ】
sm2206189    初音ミク オリジナル曲 「前へ」
sm2369047    【初音ミク】みくみくにしてあげる♪ フルコーラス版?【してやんよ】
sm2233446    平野綾でウッーウッーウマウマ(゚∀゚)
sm2398205    【底辺オリジナル】スイミー / 初音ミク
sm2438754    初音ミク・鏡音リン/レンがアホな歌詞でドラクエ3をプレイしました
sm1385804    初音ミク with Sweet Ann オリジナル曲 『Lividus』

現時点のGEMではゴミデータが出力されます。とりあえず消すには、以下を再定義してください。

module Nicovideo
  class Search
    def parse(page)
      if page.body =~ /<\/strong> を含む動画はありません。/
        @not_found = true
        raise NotFound
      end

      @total_size = page.search('form[@name="sort"]//td[@class="TXT12"]//strong').first.inner_html.to_i

      if (page/'a//img[@src="http://res.nicovideo.jp/img/common/pager_next_on.gif"]').size > 0
        @has_next = true
      else
        @has_next = false
      end

      if (page/'a//img[@src="http://res.nicovideo.jp/img/common/pager_back_on.gif"]').size > 0
        @has_prev = true
      else
        @has_prev = false
      end

      result_xpath = page/'div[@class="thumb_R"]/p[@class="TXT12"]/a[@class="video"]'
#      puts result_xpath.size.to_s
      @videos = result_xpath.inject([]) {|arr, v|
        vp = VideoPage.new(@agent, v.attributes['href'].sub(/watch\/(\w+)$/,'\1'))
        vp.title = v.inner_html
        arr << vp
      }
    end
  end
end

対象タグの動画を全件取得する

"プロの犯行"タグの付いた動画を全件取得します。

#!/usr/bin/ruby -Ku
require 'cgi'
require 'rubygems'
require 'nicovideo'

module Nicovideo
  class Search
    def initialize agent, keyword, sort=nil, order=nil, pagenum=1
      super(agent)
      @search_type = 'search'
      @keyword = CGI.escape(CGI.escape(keyword))
      @sort    = sort
      @order   = order
      @pagenum = pagenum

      params = ["videos", "total_size", "has_next?", "has_prev?"]
      self.register_getter params

      @url = url()
    end
  end

  class TagSearch
    def url
      opt = ""
      opt += '&sort='  + @sort  if @sort
      opt += '&order=' + @order if @order
      opt += '&page=' + @pagenum.to_s if @pagenum
      url = "#{BASE_URL}/tag/#{@keyword}?#{opt}"
      url
    end
  end
end

conf = YAML.load(open("conf.yaml") )
nv = Nicovideo.new(conf['mail'], conf['password'])

cnt = 0
loop do
  cnt += 1
  begin
    nv.tagsearch("プロの犯行", nil, nil, cnt).each do |vp|
      printf "%-12s %s \n", vp.video_id, vp.title
    end
  rescue Nicovideo::NotFound
    break
  end
  sleep 15
end

出力です。現時点では475件取得できました。

sm2436722    アイドルマスターアニメOP風 手書きMAD(未完成)
sm2429630    アイドルマスター 千早の誕生日を祝して『ドソジャラ』を作ってみた
sm155446     ぼくらのED 「Little Bird」ループ
sm2284869    ともだち
sm2396863    ピカチュウでウッーウッーウマウマ(゚∀゚)
sm2398743    社長室
sm2388619    【手書き】カードキャプターかぐら(未完成)
sm2243217    声優さんに歌ってもらって、オリキャラ「たまタン」のプロモ作った
sm2031011    快楽の罠 フルボイス
sm1728993    【初音ミク】  ハジメテノオト  【3D PV】
...(以下略)

pagenumなど引数がうまく反映しないので、何カ所か再定義しました。
sleepが挿んであるのは、連続アクセスによるブロック回避です。もう少し短い時間でも平気かもしれません。あまりスマートな方法には見えないので、もっとよい方法があるかも。