你必须承认Search.list https://developers.google.com/youtube/v3/docs/search/listAPI端点没有清晰的行为。这意味着你不应期望精确的结果从中。谷歌并没有记录这种行为,但这个论坛有很多来自经历过这种行为的用户的帖子。
如果您想获取给定频道上传的所有视频 ID,则应采用以下两步过程:
步骤一:获取频道上传播放列表ID。
调用Channels.list https://developers.google.com/youtube/v3/docs/channels/listAPI端点,通过其请求参数进行查询id https://developers.google.com/youtube/v3/docs/channels/list#id设置为您感兴趣的频道的 ID(或者,使用其请求参数mine https://developers.google.com/youtube/v3/docs/channels/list#mine set to true
) 用于获取该频道的上传播放列表 ID,contentDetails.relatedPlaylists.uploads https://developers.google.com/youtube/v3/docs/channels#contentDetails.relatedPlaylists.uploads.
def get_channel_uploads_playlist_id(youtube, channel_id):
response = youtube.channels().list(
fields = 'items/contentDetails/relatedPlaylists/uploads',
part = 'contentDetails',
id = channel_id,
maxResults = 1
).execute()
items = response.get('items')
if items:
return items[0] \
['contentDetails'] \
['relatedPlaylists'] \
.get('uploads')
else:
return None
请注意该功能get_channel_uploads_playlist_id
应该只被调用一次用于获取上传播放列表
给定通道的 ID;随后根据需要多次使用该 ID。
步骤2:检索播放列表的所有视频ID。
调用PlaylistItems.list https://developers.google.com/youtube/v3/docs/playlistItems/listAPI端点,通过其请求参数进行查询playlistId https://developers.google.com/youtube/v3/docs/playlistItems/list#playlistId设置为从获取的IDget_channel_uploads_playlist_id
:
def get_playlist_video_ids(youtube, playlist_id):
request = youtube.playlistItems().list(
fields = 'nextPageToken,items/snippet/resourceId',
playlistId = playlist_id,
part = 'snippet',
maxResults = 50
)
videos = []
is_video = lambda item: \
item['snippet']['resourceId']['kind'] == 'youtube#video'
video_id = lambda item: \
item['snippet']['resourceId']['videoId']
while request:
response = request.execute()
items = response.get('items', [])
assert len(items) <= 50
videos.extend(map(video_id, filter(is_video, items)))
request = youtube.playlistItems().list_next(
request, response)
return videos
请注意,当使用Google 的 Python API 客户端库 https://github.com/googleapis/google-api-python-client(像你一样做),API结果集分页 https://developers.google.com/youtube/v3/guides/implementation/pagination非常简单:只需使用list_next
与相应分页 API 端点对应的 Python API 对象的方法(如上所示):
request = API_OBJECT.list(...)
while request:
response = request.execute()
...
request = API_OBJECT.list_next(
request, response)
另请注意,上面我使用了两次fields https://developers.google.com/youtube/v3/getting-started#fields请求参数。这是一个很好的做法:仅从 API 询问实际使用的信息。
还有一个重要的注意事项:PlaylistItems.list
端点不会返回对应的项目private使用 API 密钥调用时频道的视频。当您的youtube
对象是通过调用函数构造的apiclient.discovery.build
将参数传递给它后developerKey
.
PlaylistItems.list
仅将与私有视频对应的项目返回给频道所有者。当youtube
对象是通过调用函数构造的apiclient.discovery.build
将参数传递给它后credentials
and if credentials
指拥有相应播放列表的频道。
附加重要说明:根据谷歌员工 https://issuetracker.google.com/issues/166292064#comment2,设置了上限 20000按设计通过以下方式返回的商品数量PlaylistItems.list
查询给定频道的上传播放列表时的端点。这是不幸的,但却是事实。