LoginSignup
0
1

More than 1 year has passed since last update.

Pythonでニコニコ動画とYoutubeを同時検索できるようにしてみた

Posted at

前置き

娘:おとうさん、ニコニコ動画とYoutube面白いねぇ
私:そうだね! 最高のサービスだよね!
娘:でも別々のサイトだから検索面倒臭いねぇ
私:そうだね! でもそれは仕方n
娘:面倒臭いねぇ
私:・・・きっと優秀な人が同時に検索できるサービス作ってるんじゃないかな?
娘:知らない人のサービスは触っちゃいけないっておじいちゃんが言ってた
私:・・・
娘:面倒臭いねぇ
私:・・・(無言でPCを起動する)
娘:さすがだねぇ

というわけで妄想の前置きは置いておいて、早速始めてみます。

環境

  • 今回使用するのは下記です
vscode
python
  - 3.9.7
docker
  - 20.10.11
django
  - 4.0.6

docker

  • 今回は環境作成にdockerを利用します。事前のインストール等の手順については割愛します。
  • vsCodeのコンテナ開発を利用します。
  • まずは.devcontainerフォルダを作成し、その中に必要なファイルを作成します。
devcontainer.json
{
	"name": "my YouTube",
	"dockerFile": "Dockerfile",
	"extensions": [
		"ms-python.python"
	],
}

  • 次に、DockerFileを作成します
FROM python:3

ENV PYTHONUNBUFFERED 1 
RUN pip install django
RUN pip install google-api-python-client
  • vscodeでリモート開発をスタートします。

Django

  • Djangoのプロジェクトを用意します。
  • ターミナルを利用し、以下コマンドでプロジェクトを作成します
django-admin startproject myYoutubeApp .
  • 次に、アプリケーションを作成します
python manage.py startapp youtube

YoutubeAPIキーの取得

  • Youtubeの利用にはAPIキーが必要なので、APIキーを取得します。
    既に取得済みの方は不要です。

プロジェクトの作成

  • まずは ココ にアクセスし、新規にプロジェクトを作成します。

YouTube Data API v3の有効化

  • 作成したプロジェクトを開いた状態で、ライブラリを選択します
  • YouTube Data API v3で検索をすると、今回使用するライブラリが表示されるので、クリックします。
  • 有効にするをクリックして、有効化します。

認証情報を作成

  • APIキー取得のために、認証情報を作成します
  • 認証情報をクリックして遷移した画面で、CREATE CREDENTIALSをクリックし、APIキーを選びます
  • 自動でAPIキーが作成されるので、必ずメモをしておいてください

セキュリティ

  • 最低限のセキュリティはかけておきましょう。作成したAPIキーをクリックします
  • APIの制限から、キーの制限を選択しYouTube Data API v3にチェックを入れて保存します

ニコニコ動画

  • ニコニコ動画のAPIの利用には特にキーが必要ないので、何かする必要はありません。

動画情報を取得してみる

  • まずはトップページを開けるようにします。プロジェクトのurls.pyに追記します
myYoutubeApp > urls.py
urlpatterns = [
    path('admin/', admin.site.urls),
    # 追加
    path('', include('youtube.urls')),
]
  • 次に、アプリケーションの方のurls.pyを修正します
youtube > urls.py
from django.urls import path
from . import views

urlpatterns = [
    # ルートのアクセスを定義
    path('', views.index, name='index'),
]
  • ルートにアクセスした際の処理を作成します
youtube > view.py
from django.shortcuts import render

def index(request):
    return render(request, 'index.html', {'text': 'Hello World!'})
  • アクセス先のhtmlを作成します。アプリケーションのフォルダ内にtemplatesフォルダを作成し、index.htmlを作成します
youtube > index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="robots" content="noindex noffolow">
    <title>同時検索サイト</title>
</head>
<body>
    <p>{{ text }}</p>
</body>
</html>
  • ローカル環境にアクセスしてみます。Hello Worldと表示されていれば成功です。The・シンプル!
hello world
  • さて、画面表示ができたので一旦動画情報を取得試してみます。views.pyを書き換えます。画面表示は一旦しないので、index.htmlは使用していません。
viws.py
import requests

from pprint import pprint
from googleapiclient.discovery import build

def index(request):
    # Youtubeの情報を取得する
    youtube_response_json = get_youtube_data()

    # ニコニコ動画の情報を取得する
    nico_response_json = get_niconico_data()

    # 取得した情報を出力
    pprint(youtube_response_json)
    pprint(nico_response_json)

# ニコニコ動画の情報を取得する
def get_niconico_data():
    url = 'https://api.search.nicovideo.jp/api/v2/snapshot/video/contents/search'
    
    param = {
        'q' : 'エガちゃん',
        'targets' : 'title',
        'fields' : 'contentId,title,viewCounter',
        'filters[viewCounter][gte]' : 100000,
        '_sort' : 'viewCounter',
        '_limit' : 1,
        '_context' : 'apiguide',
    }

    res = requests.get(url, params=param).json()["data"]

    return res

# Youtubeの情報を取得する
def get_youtube_data():
    youtube = build(
            'youtube',
            'v3',
            developerKey={取得したAPIキー}
        )

    response = youtube.search().list(
        q='エガちゃん',
        part='id,snippet',
        order='viewCount',
        type='video',
        maxResults=1).execute()

    return response
}
  • 再びトップページへアクセスします。
  • vscodeのターミナルに以下のように取得情報が表示されれば成功です。なお、ブラウザにはエラーが表示されると思いますが今はスルーします。
# Youtube
{'etag': 'GmRBbKt6o_U_5lxnmop9UDKhUeE',
 'items': [{'etag': '3JxWeqMPWTIIt24CykBg_U8T7R4',
            'id': {'kind': 'youtube#video', 'videoId': 'WfMEHQjHdH4'},
            'kind': 'youtube#searchResult',
            'snippet': {'channelId': 'UCTcU6mI-ucdFKdYDBekRMTQ',
                        'channelTitle': 'HoteiVEVO',
                        'description': 'Official: http://www.hotei.com HOTEI- '
                                       'Thrill [Official Music Video] A '
                                       'flashback to the mid 90s, this '
                                       'original music video represents ...',
                        'liveBroadcastContent': 'none',
                        'publishTime': '2012-11-22T09:27:11Z',
                        'publishedAt': '2012-11-22T09:27:11Z',
                        'thumbnails': {'default': {'height': 90,
                                                   'url': 'https://i.ytimg.com/vi/WfMEHQjHdH4/default.jpg',
                                                   'width': 120},
                                       'high': {'height': 360,
                                                'url': 'https://i.ytimg.com/vi/WfMEHQjHdH4/hqdefault.jpg',
                                                'width': 480},
                                       'medium': {'height': 180,
                                                  'url': 'https://i.ytimg.com/vi/WfMEHQjHdH4/mqdefault.jpg',
                                                  'width': 320}},
                        'title': '布袋寅泰 / HOTEI - スリル'}}],
 'kind': 'youtube#searchListResponse',
 'nextPageToken': 'CAEQAA',
 'pageInfo': {'resultsPerPage': 1, 'totalResults': 102105},
 'regionCode': 'JP'}

# ニコニコ動画
[{'contentId': 'sm1853698',
  'title': 'エガちゃんのパナウェーブ研究所潜入記',
  'viewCounter': 413333}]
  • 取得した情報を元に動画を画面に表示してみます。まずはview.pyのindexメソッドを修正します
youtube > view.py
def index(request):
    # Youtubeの情報を取得する
    youtube_response_json = get_youtube_data()

    youtubeList = {}
    # 必要な情報を辞書に格納する
    if youtube_response_json:
        for item in youtube_response_json['items']:
            youtubeList[item['snippet']['channelTitle']] = item['id']['videoId']

    # ニコニコ動画の情報を取得する
    nico_response_json = get_niconico_data()

    nico_list = {}
    # 必要な情報を辞書に格納する
    if nico_response_json:
        for item in nico_response_json:
            nico_list[item['title']] = item['contentId']

    return render(request, 'index.html', {
        'nicoList': nico_list,
        'youtubeList': youtubeList,
    })
  • また、今回動画の埋め込みに必要な情報はtitleとidだけなので、その2つだけ取得するようにします。こうすることで、クォーターの消費を抑えることができます。
# Youtubeの情報を取得する
def get_youtube_data():
    youtube = build(
            'youtube',
            'v3',
            developerKey={取得したAPIキー}
        )

    response = youtube.search().list(
        q='エガちゃん',
        fields='items/snippet/channelTitle, items/id/videoId', # 取得するフィールドを制限する
        part='id,snippet',
        order='viewCount',
        type='video',
        maxResults=1).execute()

    return response
}
  • 次に、index.htmlを修正します
templates > index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="robots" content="noindex noffolow">
    <title>Document</title>
</head>
<body>
      <p>ニコニコ動画検索結果</p>
        {% for key, list in nicoList.items %}
            <div>
              <script type="application/javascript" src="https://embed.nicovideo.jp/watch/{{ list }}/script?w=640&h=360"></script><noscript>
              <a href="https://www.nicovideo.jp/watch/{{list}}">{{ title }}</a></noscript>
            </div>
        {% endfor %}

      <p>youtube検索結果</p>
        {% for key, list in youtubeList.items %}
            <iframe id="ytplayer{{ forloop.counter }}" type="text/html" width="640" height="360"
            src="https://www.youtube.com/embed/{{ list }}?autoplay=1&origin=http://example.com"
            frameborder="0"></iframe>
        {% endfor %}
</body>
</html>
  • それでは、再び画面へアクセスします。取得した動画が表示されていることが確認できれば成功です! なお、埋め込み許可されていない動画については表示できませんのでご注意ください。
hello world
  • フィルターとか色々いじれるようにすれば、より欲しい情報が取れるようになると思います。その辺の微調整できる機能はまたいつか。

あとがき

私:よし、できたぞ、簡単なものだけどこれでどうだ!
娘:ありがとうおとうさん!!
娘:・・・
娘:・・・・・・
娘:・・・・・・・・・
私:(感動で声も出ないか)
娘:これ検索できないの?
私:え?
娘:いくらリロードしてもエガちゃんの同じ動画しか出てこないんだけど?
私:・・・(無言でPCを開く)
娘:さすがだねぇ

入力フォームを置いてみる

  • というわけで、このままでは永遠に同じ動画しか表示されないので検索ワードを入力できるフォームを入れてみることにします。

  • まずはフォームを作成します。アプリケーションフォルダに新しくformsフォルダを作成し、その中にindexForm.pyを作成します。

forms > indexForm.py
from django import forms

class IndexForm(forms.Form):
    searchWord = forms.CharField(
        label = '検索ワード'
    )
  • どシンプルに、検索ワードを入れる入力ボックスを追加します
  • そして、view.pyindex.htmlを最終的に以下のように修正します
youtube > view.py
import requests

from django.shortcuts import render
from googleapiclient.discovery import build
from youtube.forms.indexForm import IndexForm

def index(request):
    form = IndexForm()
    searchWord = request.POST.get('searchWord', False)

    youtubeList = {}
    if searchWord:
        # Youtubeの情報を取得する
        youtube_response_json = get_youtube_data(searchWord)

        # 必要な情報を辞書に格納する
        if youtube_response_json:
            for item in youtube_response_json['items']:
                youtubeList[item['snippet']['channelTitle']] = item['id']['videoId']

    nico_list = {}
    if searchWord:
        # ニコニコ動画の情報を取得する
        nico_response_json = get_niconico_data(searchWord)

        # 必要な情報を辞書に格納する
        if nico_response_json:
            for item in nico_response_json:
                nico_list[item['title']] = item['contentId']

    return render(request, 'index.html', {
        'form': form,
        'nicoList': nico_list,
        'youtubeList': youtubeList,
    })

# ニコニコ動画の情報を取得する
def get_niconico_data(searchWord):
    url = 'https://api.search.nicovideo.jp/api/v2/snapshot/video/contents/search'
    
    param = {
        'q' : searchWord,
        'targets' : 'title',
        'fields' : 'contentId,title,viewCounter',
        'filters[viewCounter][gte]' : 100000,
        '_sort' : 'viewCounter',
        '_limit' : 2,
        '_context' : 'apiguide',
    }

    res = requests.get(url, params=param).json()["data"]

    return res

# Youtubeの情報を取得する
def get_youtube_data(searchWord):
    youtube = build(
            'youtube',
            'v3',
            developerKey={取得したAPIキー}
        )

    response = youtube.search().list(
        q=searchWord,
        fields='items/snippet/channelTitle, items/id/videoId',
        part='id,snippet',
        order='viewCount',
        type='video',
        maxResults=10).execute()

    return response
youtube > index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta name="robots" content="noindex noffolow">
    <title>Document</title>
</head>
<body>
      <form action="/" method="post">
        {% csrf_token %}
        <div>
            {{form}}
        </div>
        <input type="submit" value="送信する">
      </form>

      <p>ニコニコ動画検索結果</p>
        {% for key, list in nicoList.items %}
            <div>
              <script type="application/javascript" src="https://embed.nicovideo.jp/watch/{{ list }}/script?w=640&h=360"></script><noscript>
              <a href="https://www.nicovideo.jp/watch/{{list}}">{{ title }}</a></noscript>
            </div>
        {% endfor %}

      <p>youtube検索結果</p>
        {% for key, list in youtubeList.items %}
            <iframe id="ytplayer{{ forloop.counter }}" type="text/html" width="640" height="360"
            src="https://www.youtube.com/embed/{{ list }}?autoplay=1&origin=http://example.com"
            frameborder="0"></iframe>
        {% endfor %}
</body>
</html>
  • 再び画面を開きます
    スクリーンショット 2022-08-07 8.11.07.png
  • フォームが追加されていることを確認できました。では検索ワード入力ボックスに育児と入れてみましょう。
    screencapture-127-0-0-1-8000-2022-08-07-08_12_08.png
  • 無事関連する動画が取得できました

本当にあとがき

私:で、できたぞ、これで好きな動画を検索できるぞ
娘:わーい!
娘:・・・
娘:・・・・・・
私:ま、まだ何か?
娘:複数キーワード検索できないの?
私:・・・
娘:あと動画の数が少なすぎて、結局みたいのが見れないんだけど?
私:・・・
娘:条件もキーワードだけしかないの? 再生数とかいいね数とかで絞り込めないの?あと・・・
私:(ダッシュ)
娘:あ、逃げた。。。ま、いいか、普通にYoutubeとニコニコ動画で見よっと
私:はぁはぁ、、、逃げれたか、、、しかしまあ言っていることは正論だな、、、娘の意見も取り入れて、ちょこちょこ手直ししていくか

〜完〜

というわけで、今回はYoutubeのAPI触ってみたいというのが目的でしたの、一旦ここまで。
気が向いたら改良するかもしれません。では!

注意点

  • YoutubeのAPIのクォーターの割り当てが、現在は10,000しかありません。(以前は50万とかあったそうですが、、、すごい削減ですね)
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1