LoginSignup
23

More than 5 years have passed since last update.

YouTube Data API (v3)のサンプルコードを解釈する。

Last updated at Posted at 2018-08-26

Pythonコードの意味を1つ1つ理解する練習

YouTube Data API (v3)を試してみようと、以下の記事を試してみることにしたものの、
pythonに対する理解不足のため、一個実行するのにかなり苦労しました。

youtubeAPIを使って特定のチャンネルの動画タイトルを取得

pythonの基礎をおさらいするつもりで、コードの意味を解釈、まとめました。


#!/usr/bin/python

import apiclient.discovery
import apiclient.errors
from googleapiclient.discovery import build
from oauth2client.tools import argparser

# Set DEVELOPER_KEY to the API key value from the APIs & auth > Registered apps
# tab of
#   https://cloud.google.com/console
# Please ensure that you have enabled the YouTube Data API for your project.
DEVELOPER_KEY = "{APIキー}" 
YOUTUBE_API_SERVICE_NAME = "youtube" 
YOUTUBE_API_VERSION = "v3" 

def youtube_search(options):
  youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
    developerKey=DEVELOPER_KEY)

  # Call the search.list method to retrieve results matching the specified
  # query term.
  search_response = youtube.search().list(
    q=options.q,
    part="id,snippet",
    maxResults=options.max_results
  ).execute()

  videos = []
  channels = []
  playlists = []

  # Add each result to the appropriate list, and then display the lists of
  # matching videos, channels, and playlists.
  for search_result in search_response.get("items", []):
    if search_result["id"]["kind"] == "youtube#video":
      videos.append("%s (%s)" % (search_result["snippet"]["title"],
                                 search_result["id"]["videoId"]))
    elif search_result["id"]["kind"] == "youtube#channel":
      channels.append("%s (%s)" % (search_result["snippet"]["title"],
                                   search_result["id"]["channelId"]))
    elif search_result["id"]["kind"] == "youtube#playlist":
      playlists.append("%s (%s)" % (search_result["snippet"]["title"],
                                    search_result["id"]["playlistId"]))

  print("Videos:\n", "\n".join(videos), "\n")
  print("Channels:\n", "\n".join(channels), "\n")
  print("Playlists:\n", "\n".join(playlists), "\n")

if __name__ == "__main__":
  argparser.add_argument("--q", help="Search term", default="ヒカキン")
  argparser.add_argument("--max-results", help="Max results", default=25)
  args = argparser.parse_args()

  assert isinstance(args, object)
  youtube_search(args)

まずはYouTube Data API (v3)を使うためにAPIキーの取得

APIキーの取得は、以下のサイトを参考にしました。
IT連合 - 入門から応用的な使い方まで【技術総合wiki】

コードの内容を1ブロックずつ確認する

#!/usr/bin/python

Pythonのファイルによく書かれている /usr/bin/env python について調べた

import apiclient.discovery
import apiclient.errors
from googleapiclient.discovery import build
from oauth2client.tools import argparser

apiclientというモジュールは古いらしく今はgoogleapiclientになっているらしい。そういえばdiscoveryというクラスが2回呼ばれているな。。。

  • oauth2clientとは

原文
oauth2client makes it easy to interact with OAuth2-protected resources, especially those related to Google APIs. You can also start with general information about using OAuth2 with Google APIs.
[google翻訳]
oauth2clientを使用すると、OAuth2で保護されたリソース、特にGoogle APIに関連するリソースとのやりとりが容易になります。また、Google APIでOAuth2を使用する際の一般的な情報から始めることもできます。

どうやらgoogleAPIでoauth2認証を行うときに使うモジュールらしいです。ちなみに読み方はOAuth(オーオース)。
そして、Oauth2認証とは、、、

  • 一番分かりやすい OAuth の説明
    なるほど、前提となるOAuth認証があって、トークンの要求と応答を標準化したものがOAuth2.0ということですね。
  • Python Module Index
    そして、oauth2clientにも沢山のモジュールがあってtoolsというのは、

原文

Command-line tools for authenticating via OAuth 2.0
Do the OAuth 2.0 Web Server dance for a command line application. Stores the generated credentials in a common file that is used by other example apps in the same directory.
[google翻訳]
OAuth 2.0経由で認証するためのコマンドラインツール
OAuth 2.0 Web Serverはコマンドラインアプリケーション用にダンスを行いますか?生成された資格情報を、同じディレクトリ内の他のサンプルアプリケーションが使用する共通ファイルに格納します。

ダンスはのせいでよくわからない文になってますけど、oauth2clientのコマンドラインツールらしいです。引数を格納してくれるのかな。

argparse モジュールはユーザーフレンドリなコマンドラインインターフェースの作成を簡単にします。プログラムがどんな引数を必要としているのかを定義すると、argparse が sys.argv からそのオプションを解析する方法を見つけ出します。argparse モジュールは自動的にヘルプと使用方法メッセージを生成し、ユーザーが不正な引数をプログラムに指定したときにエラーを発生させます。

コードの後ろの方に出てくる.add_argumentで引数を追加、格納してくれる。

# Set DEVELOPER_KEY to the API key value from the APIs & auth > Registered apps
# tab of
#   https://cloud.google.com/console
# Please ensure that you have enabled the YouTube Data API for your project.
DEVELOPER_KEY = "{APIキー}" 
YOUTUBE_API_SERVICE_NAME = "youtube" 
YOUTUBE_API_VERSION = "v3" 

各種定数を変数に格納。

  • DEVELOPER_KEY:APIキー
  • YOUTUBE_API_SERVICE_NAME:使いたいAPIサービス名を入れる。google APIがサポートしているAPIの一覧は Supported Google APIs にまとめられています。
  • YOUTUBE_API_VERSION:使いたいAPIのバージョン。サービス名一覧と同じページにバージョンも記載されています。
def youtube_search(options):
  youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION,
    developerKey=DEVELOPER_KEY)

  # Call the search.list method to retrieve results matching the specified
  # query term.
  search_response = youtube.search().list(
    q=options.q,
    part="id,snippet",
    maxResults=options.max_results
  ).execute()
  • def youtube_search(options):youtube_searchという関数を定義。optionsという引数をとります。
  • youtube = build(YOUTUBE_API_SERVICE_NAME, YOUTUBE_API_VERSION, developerKey=DEVELOPER_KEY)では、上で格納した変数を使って、 youtubeというインスタンスをビルドしています。

build the service object
Whether you are using simple or authorized API access, you use the build() function to create a service object. It takes an API name and API version as arguments. You can see the list of all API versions on the Supported APIs page. The service object is constructed with methods specific to the given API. To create it, do the following:
from apiclient.discovery import build
service = build('api_name', 'api_version', ...)

build(serviceName, version, http=None, discoveryServiceUrl=DISCOVERY_URI, developerKey=None, model=None, requestBuilder=HttpRequest, credentials=None, cache_discovery=True, cache=None) 
  • search_response = youtube.search().list(では以下の検索結果を変数search_responseへと格納しています。
    • .search( ) : 以下のListメソッドで指定した検索を行います。
    • .list( ) :
      • q=options.q, :q パラメータは検索クエリを指定します。optionsは関数の引数で、今回のコードではargparseによりコマンドライン引数が格納されています。.qで格納された引数にアクセスできます。("--q"で指定)
      • part="id,snippet", :「part パラメータには、API レスポンスに含める 1 つまたは複数の search リソースのプロパティをカンマ区切りリストの形式で指定します。このパラメータに指定できる part 名は id と snippet です。」と書いてあるがよくわからんです・・・。
      • maxResults=options.max_results :「maxResults パラメータには、結果セットとして返されるアイテムの最大数を指定します。0 以上 50 以下の値を指定できます。デフォルト値は 5 です。」とあります。optionsは関数の引数で、今回のコードではargparseによりコマンドライン引数が格納されています。.max_resultsで格納された引数にアクセスできます。("--max-results"で指定)
  videos = []
  channels = []
  playlists = []

これは、結果を格納するための空リストを準備します。

  # Add each result to the appropriate list, and then display the lists of
  # matching videos, channels, and playlists.
  for search_result in search_response.get("items", []):
    if search_result["id"]["kind"] == "youtube#video":
      videos.append("%s (%s)" % (search_result["snippet"]["title"],
                                 search_result["id"]["videoId"]))
    elif search_result["id"]["kind"] == "youtube#channel":
      channels.append("%s (%s)" % (search_result["snippet"]["title"],
                                   search_result["id"]["channelId"]))
    elif search_result["id"]["kind"] == "youtube#playlist":
      playlists.append("%s (%s)" % (search_result["snippet"]["title"],
                                    search_result["id"]["playlistId"]))
  • for search_result in search_response.get("items", []):

    for文で変数search_responseから、.getメソッドで第一引数"items"というキーの値を取得します。もし、第一引数で指定したキーが存在しない場合は、第二引数に設定したからのリスト"[ ]"を返します。

    Pythonの辞書のgetメソッドでキーから値を取得(存在しないキーでもOK)

  • if search_result["id"]["kind"] == "youtube#video":

    検索結果search_resultの中のリストidの中のkindが”youtube#video”だったら

  • videos.append("%s (%s)" % (search_result["snippet"]["title"],
    search_result["id"]["videoId"]))


    リストvideosの中に文字列"%s(%s)"を追加(append)する。なお、それぞれの%sには、検索結果search_resultの中のリストsnippetの中のtitleと、リストidの中のchannelIdをいれます。
    Python文字列操作マスター

  • elif search_result["id"]["kind"] == "youtube#channel":
    上と同じ解釈

  • elif search_result["id"]["kind"] == "youtube#playlist":

  • 上と同じ解釈

  print("Videos:\n", "\n".join(videos), "\n")
  print("Channels:\n", "\n".join(channels), "\n")
  print("Playlists:\n", "\n".join(playlists), "\n")
  • print("Videos:\n", "\n".join(videos), "\n")

    1. videos:(改行)と出力
    2. リストvideosの中身を改行でjoin(連結)して出力 便利!joinの使い方まとめ
    3. 最後に改行を出力
  • print("Channels:\n", "\n".join(channels), "\n")
    上と同じ解釈

  • print("Playlists:\n", "\n".join(playlists), "\n")
    上と同じ解釈

if __name__ == "__main__":
  argparser.add_argument("--q", help="Search term", default="ヒカル")
  argparser.add_argument("--max-results", help="Max results", default=25)
  args = argparser.parse_args()
  • if __name__ == "__main__":は、要するに

「if name == ‘main’:」の意味は、「直接実行された場合のみ実行し、それ以外の場合は実行しない」という意味だったのです。 (【Python入門】モジュールを扱う際に重要な「if name == ‘main’:」とは?)

ということらしいです。コードから、このプログラムは単体実行されることを想定しているようです。

  • argparser.add_argument("--q", help="Search term", default="ヒカル")
    この記事の上の方で軽く触れたargparseモジュールに関連する記述です。"--q"はオプショナル引数といいます。

オプショナル引数(Optional Arguments)を指定することで、任意のパラメータを取得することができます
[Python] argparseモジュールを使って、コマンドライン引数を本格的に扱う

 help="Search term"はヘルプ用の文言。default="ヒカル"は、引数がなかった時のデフォルト値を指定します。

  • argparser.add_argument("--max-results", help="Max results", default=25)
    上と同じ解釈

  • args = argparser.parse_args()
    引数が入ったオブジェクトをargsとしてインスタンス化します。

  assert isinstance(args, object)
  youtube_search(args)

assert文は条件式がTrueではない時に例外を投げる文です。[Python] assert文で超お手軽テスト
isinstance関数は変数などのオブジェクトの型を取得して確認したり、特定の型であるかを判定したりする関数です。今回のコードでは変数argsがobjectかどうかを判定しています。Pythonで型を取得・判定するtype関数, isinstance関数
youtube_search(args)は、上で定義したyoutube_search関数に引数argsを渡す処理です。

以上、文脈も体裁もハチャメチャですが1つの簡単なプログラムを真面目に見ていくといろいろな要素が詰まってて面白いなーと思いました。

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
23