質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

YouTube API

YouTube APIはYouTubeのビデオコンテンツと機能性をウェブサイト、アプリケーション、デバイスに統合することを可能にします。

Q&A

解決済

2回答

1162閲覧

pythonでYouTube Data APIを用いて特定のチャンネルが配信中であるかどうかを判定したい。

gragonfly0808

総合スコア14

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

YouTube API

YouTube APIはYouTubeのビデオコンテンツと機能性をウェブサイト、アプリケーション、デバイスに統合することを可能にします。

0グッド

0クリップ

投稿2023/03/05 11:13

編集2023/03/05 13:10

pythonでYouTube Data APIを用いて特定のチャンネルが配信中であるかどうかを判定するプログラムを書いています。以下のようなコードを書いてみたのですが、serch().lisy()で取得される情報が配信中の動画のIDではなく、一つ前の動画のIDを取得してしまうため、実際に配信中のチャンネルであっても配信していないという判定になってしまいます。video().list()に手動で配信中んぼ動画のIDを入れた場合は、正しく動作します。
以下が、作成したコードです。

python

1from googleapiclient.discovery import build 2from datetime import datetime, timedelta 3 4 5api_key = '自分のAPIキー' 6youtube = build('youtube', 'v3', developerKey=api_key) 7 8def youtube_search(channel_id: str) -> list: 9 # Search: list で channel_id から検索する 10 search_response = youtube.search().list(channelId=channel_id, part='id', order='date', maxResults=1).execute() 11 return search_response.get('items', []) 12 13def youtube_video_details(video_id: str) -> list: 14 # Videos: list で video_id から検索する 15 video_response = youtube.videos().list(id=video_id, part='liveStreamingDetails').execute() 16 return video_response.get('items', []) 17 18if __name__ == '__main__': 19 for item in youtube_search('チャンネルID'): 20 video_id = item['id']['videoId'] 21 details = youtube_video_details(video_id) 22 23print('########################################################################') 24 25try: 26 scheduled_start_time = datetime.strptime(details[0]['liveStreamingDetails']['actualEndTime'], '%Y-%m-%dT%H:%M:%SZ') 27 scheduled_start_time_jst = scheduled_start_time + timedelta(hours=9) # 日本時間(JST)にする 28 print(video_id, scheduled_start_time_jst, '現在、配信は行われていません。') 29except: 30 print('現在、配信中') 31 32 33print('#################') 34print(youtube_search('チャンネルID'))

このコードの作戦としては、配信中の動画の場合はactualEndTimeが存在しないことに着目して 最新の動画のactualEndTimeを取得しようとしたときにエラーになるかどうかで、配信中かどうかを確認しようとしました。
実行結果の詳細は、以下の通りです。
weather newsのような四六時中配信している特殊なチャンネルであれば、配信中の判定ができる。
個人の配信者の方、数人をサンプルに試したところ、配信中の方のチャンネルIDを入力して実行しても配信中判定にはならなかった。

ご指導の程、よろしくお願いします。

[追記]
一部のチャンネルでは、正常な動作をしました。
配信者特有のいわゆる「待機所」という形の特殊な枠(動画の判定でAPIが取得しているかは謎ですが)が何か悪さをしている気がしてきました。(本配信以外で配信予定の枠をとっているチャンネルでは、配信中にも関わらず、配信中の判定になりませんでした。逆に、本配信のみでチャンネルが動いているものに関しては、正常に配信中の判定になりました。)片っ端から実験した結果、この推測にたどり着きました。
おそらくですが、APIがライブ配信であることを認識する形式の動画形式が、複数あることで挙動が不安定になると思われます。ライブ配信とプレミアム公開の動画が同じ判定をされるようなので、そのことも絡んでいるのかもしれません。(一応、最新の動画IDを取得する形にはしているのですが...)
ライブ配信を一つのチャンネルで複数行っている場合は、正しく配信中の判定になっていました。抽出された動画は、最も新しく配信を開始した動画になりました。(WeatherNewsで調査)
待機所を用意しているチャンネルであっても、ライブ配信をしていないときは最新の配信のアーカイブの動画IDを取得しました。
待機所を用意しているチャンネルが配信中の時に、上記のプログラムを実行した場合は、最新の動画アーカイブでもない"比較的"新しい動画IDが出力されました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gragonfly0808

2023/03/05 11:32 編集

過去に投稿した質問と同じ内容の質問というご指摘をいただきましたが、指摘の対象となっていると思われる過去の質問の投稿はすでにteratail様に削除依頼をしています。前回の質問の投稿では、質問内容が丸投げであるというご指摘を受けましたので、より具体的な質問内容に変更した次第です。過去の質問内容を編集すべきだというご意見を持たれる方もいらっしゃると思いますが、すでに前回の質問の投稿についての削除依頼をしてしまっていたので、新たに内容を具体的にして質問した次第です。 ご指導の程、よろしくお願いします。
guest

回答2

0

ベストアンサー

参考記事
https://qiita.com/mizunana/items/8acc66b48a2584321ff5

参考記事の書き方に倣うと以下リクエストはどうでしょうか
Search:list
投げるRequest
part=snipet,channelId=[チャンネルID],eventType=live,type=video

返ってくるjsonのkey "items"の値が配信中であればその動画の情報、配信していなければ空になります。

投稿2023/03/06 01:43

hawawa

総合スコア79

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gragonfly0808

2023/03/06 01:58

回答していただき、ありがとうございます! お示ししていただいた回答を元に以下のようなコードを書いてみました。 目的の実行結果を出力することができました。 ありがとうございます! 以下、コード ```python from googleapiclient.discovery import build from datetime import datetime, timedelta API_KEY = "" youtube = build('youtube', 'v3', developerKey=API_KEY) channel_id = '' #completed -> 配信完了 #live -> 配信中 #upcoming -> 待機所 eventType = "completed" response = youtube.search().list( part='id,snippet', channelId=channel_id, eventType=eventType, type='video', order="date", maxResults=1 ).execute() print('#####################Searchの実行結果###########################') print(response) def youtube_search(channel_id: str) -> list: search_response = youtube.search().list( part='id,snippet', channelId=channel_id, eventType=eventType, type='video', order="date", maxResults=1 ).execute() return search_response.get('items', []) def youtube_video_details(video_id: str) -> list: video_response = youtube.videos().list( id=video_id, part='liveStreamingDetails' ).execute() return video_response.get('items', []) try: for item in youtube_search(channel_id): video_id = item['id']['videoId'] details = youtube_video_details(video_id) scheduled_start_time = datetime.strptime(details[0]['liveStreamingDetails']['actualStartTime'], '%Y-%m-%dT%H:%M:%SZ') scheduled_start_time_jst = scheduled_start_time + timedelta(hours=9) # 日本時間(JST)にする print('#####################ライブ配信の状況###########################') print('VideoID: ', video_id) print(scheduled_start_time_jst, 'からライブ配信が行われています。') except: print('#####################ライブ配信の状況###########################') print('現在、ライブ配信は行われていません。') ```
hawawa

2023/03/06 02:02

当方pythonは分からないのですがお役に立ててよかったです。
guest

0

(コードのインデントは別として)

serch().lisy()で取得される情報が配信中の動画のIDではなく、一つ前の動画のIDを取得してしまう
待機所を用意しているチャンネルであっても、ライブ配信をしていないときは最新の配信のアーカイブの動画IDを取得しました。
待機所を用意しているチャンネルが配信中の時に、上記のプログラムを実行した場合は、最新の動画アーカイブでもない"比較的"新しい動画IDが出力されました。

これは YouTube API のバグです。
(order = date を指定しても、常にpublished_dateの降順に、最新の動画を含めた動画情報を返すとは限らない。直近の動画が取得できない場合がある)

また、時間帯やAPIを利用するユーザー、検索対象のチャンネルによっても状況は変わります。
自分が試した限りでは、複数のチャンネルで正しく取得できています。

これに限らず、YouTube API はずっと前から環境依存・ユーザー依存・時間依存のバグが数多く存在しており、しかもまともにドキュメントされていません。
たまに試すと直っている場合も多いです。
ユーザー依存・時間依存なのでうまくいく人もいればうまくいかない人もいます。(なのでバグ情報も出回りにくいです)

配信者特有のいわゆる「待機所」という形の特殊な枠(動画の判定でAPIが取得しているかは謎ですが)が何か悪さをしている気がしてきました。

待機所は、「actualStartTime だけがあって actualEndTime が存在しない」、または 「actualStartTime も actualEndTime も存在しない」のパターンであるため、質問者さんのコード(actualEndTimeの有無だけで区別)では配信中の動画と区別できません。

待機所であるかどうかは actualEndTime の不存在に加えて下記のように判定します。

items = youtube.videos().list(id=video_id, part='id,snippet,liveStreamingDetails').execute() で情報を取得したとき: ・ items[0]['snippet']['publishedAt'] が 半年以上、1年以上前などかなり古い(ただしチャンネルによっては直近に待機所を立て直したりしている場合もあるため一概には言えません) ・ items[0]['snippet']['liveBroadcastContent'] が 'upcoming' である。 (配信予定やプレミア公開の公開予定の場合にも liveBroadcastContent はupcoming になるので上記publishdAt と組み合わせて判定する) (actualStartTimeが存在する場合は upcoming ではないのでこれだけで判断できない) 上記によっても、配信予約を入れたまま放置している動画もたまにあるので、100%うまくいくとは限りません。

ただし、上記のように、「order = date を指定しても、常にpublished_dateの降順に、最新の動画を含めた動画情報を返すとは限らない」バグが発生している場合、待機所が最新の動画として取得される場合があるため、うまく動作しません。

ライブ配信とプレミアム公開の動画が同じ判定をされる

その通りです。
そしてライブ配信とプレミアム公開を、 YouTube API を用いて区別する方法は、現状存在しません。
(ただし配信中のライブ配信と、チャット欄が閉じたプレミアム公開は区別できる可能性はあります)
スクレイピングすれば不可能ではないかもしれませんが、YouTubeのスクレイピングは利用規約上禁止されています。
(APIが商用レベルでは使い物にならない&コストが高いため、ランキングサイトなどの多くは裏では黙ってスクレイピングしていると推測します(スクレイピングを推奨する意図は全くありません))

投稿2023/03/05 13:09

編集2023/03/05 14:09
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gragonfly0808

2023/03/06 02:05

ご回答していただきありがとうございます! youtube Data APIにも、バグがあることは知らなかったです。 バグが発覚した時点で、ドキュメントに記載してほしいものですね。 APIのバグの除去や機能の追加を早急に行わないと、そのうちスクレイピングがされる量が増えて、サーバーが一時的に落ちてしまう被害が発生するかもしれませんね。 とても詳細に回答していただき、とても助かりました。 今後、Youtbe Data APIを使ったプログラムで目的の動作をしないときは、既知のバグである可能性も視野に入れてデバッグをしていこうと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問