YouTube Data API による動画一覧取得
YouTube の、あるチャンネルの動画一覧を取得しよう、という時に、それ自体は、検索APIが提供されているので、可能ではあります。
各言語での例も提供されています。
こういう構造のデータが取得できる。
実際のデータ部はこの形。
Search API だと、duration が取れないのが残念。
ごく簡単な例としてはこんな感じになります。
from apiclient.discovery import build
import json
# API情報
API_KEY = 'xxx'
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'
youtube = build(
YOUTUBE_API_SERVICE_NAME,
YOUTUBE_API_VERSION,
developerKey=API_KEY
)
search_response = youtube.search().list(
channelId='UC7ovu6a8ydIbDy0fAKmoZ9A',
part='snippet',
maxResults=50,
).execute()
with open("response.json", mode="w", encoding="utf-8") as f:
json.dump(search_response, f, ensure_ascii=False, indent=2)
python3 response.py
とやれば、response.json が出力されます。(謎のchannelId・・・)
ところが、みなさん、苦労されているわけです。
理由の一つは、maxResults の最大値が50であること。
すなわち、一回の検索で、50件しか取得できません。
これを超える動画を保有しているチャンネルの場合は、ループしながら取得する必要があります。
そのための仕組みとして、pageToken というものが提供されており、maxResults を超える結果がある場合は、nextPageToken が返却されるので、次の検索をする際に、pageToken として nextPageToken を渡してあげれば、次のデータを取得できます。
この処理を書かなければいけないということはありますが、それでも、そのような仕様が提示されているので、そこもまだ良いです。
問題は、この仕組みで検索していっても、取得件数が500件くらいになると、nextPageToken が返って来なくなります。これがつらい。
そこでこちらの方は、期間を絞って取得したら、もう少しなんとかなりますよ、ということを書いていただいています。
500件未満になる程度の期間条件をつけて検索すれば、その期間分は取得できる。
また、期間を変えて検索すれば、また500件取得できる、という形です。
ということで、こんな感じで書いてみました。
こちらの例は、取得結果から、一部項目を取り出して、新しいjsonファイルを出力する、というものです。
from apiclient.discovery import build
import json
import datetime
from dateutil.relativedelta import relativedelta
# API情報
API_KEY = 'xxx'
YOUTUBE_API_SERVICE_NAME = 'youtube'
YOUTUBE_API_VERSION = 'v3'
videos = [] #videoURLを格納する配列
def youtube_search(pagetoken, st, ed):
youtube = build(
YOUTUBE_API_SERVICE_NAME,
YOUTUBE_API_VERSION,
developerKey=API_KEY
)
search_response = youtube.search().list(
channelId='UCbDEamSXQhxqhovhd2NdEyg',
part='snippet',
type='video',
maxResults=50,
publishedAfter=st, #'2013-01-01T00:00:00Z',
publishedBefore=ed, #'2014-01-01T00:00:00Z',
pageToken=pagetoken
).execute()
print(search_response["pageInfo"]["totalResults"])
for search_result in search_response.get("items", []):
if search_result["id"]["kind"] == "youtube#video":
d = {'title': search_result["snippet"]["title"],
'description': search_result["snippet"]["description"],
'keywords': '',
'source': 'junyiacademy',
'inherentProperties' : {
'id': search_result["id"]["videoId"],
'url': 'https://www.youtube.com/watch?v=%s' % search_result["id"]["videoId"],
'thumbnailUrl': search_result["snippet"]["thumbnails"]["default"]["url"],
'publishedAt': search_result["snippet"]["publishedAt"],
}
}
videos.append(d)
# print(search_result["snippet"]["title"])
try:
nextPagetoken = search_response["nextPageToken"]
# print(nextPagetoken)
youtube_search(nextPagetoken, st, ed)
except:
return
dt = datetime.datetime(2016, 1, 1, 0, 0)
for i in range(1, 2):
print(dt.isoformat())
youtube_search('', dt.isoformat()+'Z', (dt + relativedelta(months=1)).isoformat()+'Z')
dt = dt + relativedelta(months=1)
with open("videolist.json", mode="w", encoding="utf-8") as f:
json.dump(videos, f, ensure_ascii=False, indent=2)
for i in range(1, 2) のところを変えてあげれば○ヶ月分のデータを取得できる、というものです。
1ヶ月では広かったり狭かったりしたら、+ relativedelta(months=1) の部分を変えれば良いわけです。
ところが、これで話は終わりませんでした。
YouTube Data API では 1 日あたりのクォータ量が定められています。
無料で使えるのは、Queries /日:10,000と書かれています。
※[IAM と管理] にある [割り当て] ページで、割り当て上限の増加のリクエストや他のサービスの割り当ての確認ができます。
ただ、この「Queries」というのは、youtube.search().list を投げられる数ということではなくて、取得する情報量等も考慮されたボリュームです。
上記プログラムで取得すると3600件ちょっと取得するのが1日の最大量のように感じられます。
これは逃れようがありません。
なので、これを超えないボリュームを見計らって、何ヶ月分取得するかを定める、その分取得したら、翌日まで待つ、ということになります。
しかし1日は長いな・・・
もう一点。
上記で、print(search_response["pageInfo"]["totalResults"]) ということをやっています。
この場合は、この1ヶ月分のデータ件数が取得できるはずなのですが、どうもこの出力と実際の出力件数が異なります。
・・・と思いましたが、type='video' を指定せずに、if search_result["id"]["kind"] == "youtube#video": という形で絞っていたからかも。
検索時点でtype を指定しておけば、取得情報ボリュームも抑えられることになるので、3600件よりもう少し取得できるかもしれないですね。
Discussion