🎉

niconico動画のAPIクライアントを作ってみた

2021/12/03に公開

はじめに

この記事は ICT Advent Calendar2021 3日目の記事です!

この度、ニコニコ動画 『スナップショット検索API v2』 の非公式クライアントを制作したので、そのお披露目記事となります。

昨日の記事はからあげさんの 高専プロコンを自分なりに振り返る です。
彼は僕が5年生のときに1年生だったので、認知してもらえているのは非常に嬉しいですね。

ICT委員会へはOBとしての活動しかできませんが、みんないろいろと頑張ってくれるといいな〜っと空から応援しています。

スナップショット検索API v2 とは

株式会社ドワンゴ 様の提供している、ニコニコ動画の動画情報を取得できるAPIです。

動画の再生数・投稿時刻・説明文などの検索・取得を行うことができます。

例:

リクエスト

curl -A 'apiguide application' 'https://api.search.nicovideo.jp/api/v2/snapshot/video/contents/search?targets=title&fields=contentId,title,viewCounter&_sort=-viewCounter&_offset=0&_limit=3&_context=apiguide_application' --data-urlencode "q=初音ミク" --data-urlencode "filters[viewCounter][gte]=10000"

レスポンス

{
  "meta": {
    "status": 200,
    "totalCount": 12673,
    "id": "0554268c-c0f3-4436-9098-7b9e07885623"
  },
  "data": [
    {
      "contentId": "sm1097445",
      "title": "【初音ミク】みくみくにしてあげる♪【してやんよ】",
      "viewCounter": 11904784
    },
    {
      "contentId": "sm1715919",
      "title": "初音ミク が オリジナル曲を歌ってくれたよ「メルト」",
      "viewCounter": 10230124
    },
    {
      "contentId": "sm15630734",
      "title": "『初音ミク』千本桜『オリジナル曲PV』",
      "viewCounter": 9557201
    }
  ]
}

(※公式ガイドより抜粋)

このように、必要なパラメータを組み立てたURLを叩くことで、ニコニコ動画のコンテンツを検索することができる大変便利なものになっています。

(実際、筆者も個人用の VOCALOID ランキング通知 bot で利用しています)

しかし、

  • 毎回URLを組み立てるのが面倒
  • typo した場合に気づくことが困難
  • 最大同時に100件までしか取得できない
  • リクエスト間に遅延を挟む必要がある

など、いくつか使いづらい点が存在し、特にプログラムから叩く際にはクライアントがあった方がより使いやすいだろうと考え、実装しました。

NicoApiClient とは

NicoApiClient は、『スナップショット検索API v2』の非公式クライアント (Python 実装) です。

主に筆者である Javakky が機能提案とレビュー、 yashiroyrahs が実装を担当しています。

インストール

PyPI にアップロードしているため、 pippoetry で簡単に追加することができます。

pip install nicovideo-api-client
poetry add nicovideo-api-client

使い方

使い方のサンプルを一つ例に挙げます。

request = (
  SnapshotSearchAPIV2()
  .tags_exact() # タグ完全一致検索を行う
  .query("VOCALOID") # "VOCALOID" を検索
  .field(
    {
      FieldType.TITLE, # タイトル
      FieldType.VIEW_COUNTER, # 再生回数
    }
  ) # レスポンスに含める要素を指定
  .sort(FieldType.VIEW_COUNTER, True) # 再生回数の少ない順にソート
  .simple_filter() # 絞り込み方法を指定する
  .filter(
    {
      FieldType.VIEW_COUNTER: {"gte": 1000, "lt": 10000} # 再生回数が 1000 ≦ x < 10000
    }
  ) # 絞り込み条件を設定する (省略可)
  .limit(101) # 取得件数を設定する
  .user_agent("NicoApiClient", "0.5.0") # このAPIを利用しているあなたのサービスの名称とバージョンを設定する
)

print(request.build_url())
# https://api.search.nicovideo.jp/api/v2/snapshot/video/contents/search?targets=tagsExact&q=VOCALOID&fields=title,viewCounter&_sort=%2BviewCounter&filters[viewCounter][gte]=1000&filters[viewCounter][lt]=10000
print(request.request().json())
# {
#   'meta': {'id': '検索のリクエストID', 'totalCount': 20000, 'status': 200},
#   'data': [
#     {'title': 'タイトル1', 'viewCounter': 9999}, ... 
#   ]
# }

このように NicoApiClient を利用することで、簡単にスナップショット検索APIのURLを組み立てられる他、分割リクエストなどにも対応し簡単にデータの取得を行うことができるようになります!

(100件以上の取得がリクエストされた場合には100件ごとに区切って取得します)

これらのチェーンしたメソッドは、各々が次に呼ばれるべきメソッドのみを持ったインスタンスを返すという実装となっているため、次に呼び出すべきメソッドが補完に出てきて体験がよいです (自画自賛)

filter 周りだけ、 (型検査で以上な値は弾けるものの) 複雑な辞書型を要求するため改善を検討中です。

ここからは、各種検索メソッドの使い方についてみていきましょう!

検索対象

SnapshotSearchAPIV2 のインスタンスを作成したら、まずは検索対象を選択します。

タグ完全一致検索

いわゆるタグ検索というやつです。次項で説明するクエリに設定した文字列と完全に一致するタグを持つ動画を検索します。

SnapshotSearchAPIV2()
  .tags_exact()
  .query("VOCALOID") # 「VOCALOID」タグの動画を検索する

キーワード検索

niconico動画 の検索バーと同じ検索手法です。

タイトル、説明文、タグ にクエリが含まれる場合にヒットします。

SnapshotSearchAPIV2()
  .keywords()
  .query("VOCALOID") # 「VOCALOID」を含む動画を検索する

ターゲット指定検索

検索に利用するターゲットを指定して検索します。

nicovideo_api_client.constants.target_types に含まれる FieldType を指定できます。

SnapshotSearchAPIV2()
  .targets({FieldType.TITLE, FieldType.DESCRIPTION})
  .query("VOCALOID") # タイトルか説明文に「VOCALOID」を含む動画を検索する

クエリ設定

検索文字列を設定します。

AND・OR検索

.and_ メソッドをチェーンさせることで、AND・OR検索を行うことができます。

各メソッドの引数に文字列のリストを渡すことで OR 条件を設定できます。

.query("VOCALOID")
  .and_(["初音ミク", "鏡音リン"])
  .and_(["MMD"]) # "VOCALOID 初音ミク OR 鏡音リン MMD" と等価

直接クエリ入力

APIガイドに記されている構文に従って検索クエリを指定できます。

.query("VOCALOID OR VOICEROID")

キーワードなし検索

キーワードを指定せずに検索を行います。 (※非推奨)

こちらを選択した場合、APIサーバーへの負荷を軽減するためフィルターの設定が必須となります。

実はフィルターの設定によってはすり抜けることも可能ですが、すり抜けてもただ検索が重くなるだけな上に最悪の場合、利用停止や損害賠償を請求される可能性もあるため、慎重に利用しましょう。

.no_keyword()

検索フィルター

filters

シンプルな設定が行えるフィルタで、指定された条件のいずれかに一致するコンテンツが全て取得されます。

.filter({
  FieldType.VIEW_COUNTER: [1000, 10000],
  FieldType.MYLIST_COUNTER: {"gt": 10, "lte": 100},
}, True)

第一引数には、絞り込み対象とする FieldType をキーとした辞書を渡すことができます。

この辞書の値にはリストまたは辞書を渡すことができ、それぞれの使い方は以下の通りです。

  • リスト
    • リストに含まれる値のどれかと一致するように値を絞り込みます。
  • 辞書
    • キーには gt, gte, lt, lte が指定できます。
    • それぞれ検索結果が渡された値の 超過、以上、未満、以下 となるように絞り込みます。

第二引数に False を渡した場合、リストと辞書が同時に指定されることを抑制できます。

jsonFilter

こちらは、 and, or, not などを組み合わせ、より詳細な絞り込みができるようになったフィルターです。

JsonFilterOperator には or_, and_, not_ が用意されており、入れ子にすることが可能になっています。

下の例では、2021年1月1日以降 または 2010年1月1日以前 に投稿された動画を取得するように絞り込まれます。

.json_filter(
  JsonFilterOperator.or_( # 以下の条件のどちらか
    JsonFilterTerm.set_range( # ある値が範囲に含まれるかを判定する
      FieldType.START_TIME, # 投稿時間が
      from_=datetime(2021, 1, 1, 0, 0, 0), # 2021年1月1日以降
      include_lower=True, # 0時0分ちょうどを含む
    ),
    JsonFilterTerm.set_range(
      FieldType.START_TIME, to_=datetime(2010, 1, 1, 0, 0, 0)
    ),
  )
)

おわりに

個人的には非公式APIを叩くためのクライアントも持っていたりするのですが、一旦こちらは公式で提供されているAPIのみを叩くクライアントとさせていただきました!

これでもニコニコのデータ分析などに使うには十分なデータの取得が可能ですので、ぜひ使ってみてください!
個人的には、ユーザー検索 (https://nvapi.nicovideo.jp/v3/) とマイリスト検索 (https://nvapi.nicovideo.jp/v2/) の API くらいは公開して欲しいな〜と思っているのですが、どうなるのでしょうか。

ここ最近でデータ分析というと Youtube が主流な気もしますが、試しに使ってみてはいかがでしょうか!

Discussion