首页 > 解决方案 > Youtube Data Api Page Token Question (python)

问题描述

我尝试下载 2019 年的视频元数据。每次运行我的代码时它都超过了配额限制。在那段时间里,我有不到 100 个视频。谁能告诉我一个更好的方法来编写代码?

   try: 
    request = youtube.search().list(
        part = 'id, snippet',
        type = 'video',
        publishedAfter = '2018-12-31T23:59:59Z',
        publishedBefore = '2020-01-01T00:00:00Z',
        order = 'date',
        fields = 'nextPageToken,items(id,snippet)',
        pageToken = None,
        maxResults = 50
    )
    response = request.execute()
    nextPageToken = None

    while True:
        request = youtube.search().list(
        pageToken = nextPageToken,
        part = 'id, snippet',
        type = 'video',
        fields = 'nextPageToken,items(id,snippet)',
        maxResults = 50
        )

        response = request.execute()
        nextPageToken = response['nextPageToken']
        items = response['items']
        if response['nextPageToken'] == None:
            break
        for each_item in items:
            video_id = each_item['id']['videoId']
            sub_items = each_item['snippet']
            for sub_item in sub_items:
                video_item[sub_item] = sub_items[sub_item ]

            video_data[video_id] = video_item
except Exception as e:
    print('Error in get_video_data: {0}'.format(e))

谢谢!

标签: pythonyoutube-data-api

解决方案


请确认您对Search.list端点的 API 调用是针对该一年期间的整套 YouTube 视频运行的;您的 API 调用未指定任何其他过滤条件,这意味着您的查询(在分页时)可能会返回数百万个视频条目

如果实际上您正在寻找自己的视频,那么您的Search.list端点调用应该包括 theforMinechannelIdrequest 参数:

  • 当您使用其参数youtube从方法构造对象时(即您正在发出授权请求),然后使用请求参数,如下所示:discovery.buildcredentialsforMine
request = youtube.search().list(
    forMine = True,
    part = 'id,snippet',
    type = 'video',
    publishedAfter = '2018-12-31T23:59:59Z',
    publishedBefore = '2020-01-01T00:00:00Z',
    order = 'date',
    fields = 'nextPageToken,items(id,snippet)',
    maxResults = 50
)

请注意,根据下面更新和修复部分中记录的调查结果,这种替代方法被证明是不可行的。

  • 当您使用其参数youtube从方法构造对象时(即您没有发出授权请求),然后使用请求参数,如下所示:discovery.builddeveloperKeychannelId
request = youtube.search().list(
    channelId = CHANNEL_ID,
    part = 'id,snippet',
    type = 'video',
    publishedAfter = '2018-12-31T23:59:59Z',
    publishedBefore = '2020-01-01T00:00:00Z',
    order = 'date',
    fields = 'nextPageToken,items(id,snippet)',
    maxResults = 50
)

请注意,这CHANNEL_ID是您的频道(或任何其他频道)的 ID。

上述两种 API 调用之间的区别如下:发出授权请求时(上面的第一个项目符号),您将获得您频道的所有视频,包括那些非公开的视频(即那些privacyStatus设置为privateunlisted);另一方面,当使用 API 密钥(上面的第二个项目符号)时,即使是您自己频道的 ID,您也只会获得公共视频(即那些privacyStatus设置为的视频)。publicCHANNEL_ID


现在,不幸的是,您上面的代码还有另一个问题:您的两个Search.list端点调用不相同,以pageToken请求参数为模。那是因为第二次调用没有获取到请求参数publishedAfterpublishedBefore.

这种差异意味着您没有正确分页第一个 API 调用的结果集(实际上,即使将参数传递pageToken给第二个 API 调用)。

幸运的是,您正在使用的用于 Python 的 Google 的 API 客户端库以简单的Python 方式实现了API 结果集分页(我将在上面第二个项目符号的情况下举例说明):

request = youtube.search().list(
    channelId = CHANNEL_ID,
    part = 'id,snippet',
    type = 'video',
    publishedAfter = '2018-12-31T23:59:59Z',
    publishedBefore = '2020-01-01T00:00:00Z',
    order = 'date',
    fields = 'nextPageToken,items(id,snippet)',
    maxResults = 50
)
video_data = {}

while request:
    response = request.execute()

    for item in response['items']:
        video_id = item['id']['videoId']
        video_item = item['snippet']
        video_data[video_id] = video_item

    request = youtube.search().list_next(
        request, response)

上面的代码表明不需要完整地重复第一个 API 调用,并添加一个pageToken参数;有更简单的陈述就足够了:

    request = youtube.search().list_next(
        request, response)

该语句使用对象的nextPageToken属性值response从旧request对象构造一个具有正确设置pageToken属性的新对象。


更新和修复

Search.list在对请求参数的调用进行进一步的测试和调查后,forMine如上所述,我得出以下结论:publishedAfterpublishedBefore

  • 给出的参数forMine=True没有任何参数publishedAfterpublishedBefore并使 API 调用按预期工作;

  • 与任何参数forMine=True一起给出的参数publishedAfterpublishedBefore/或两者都会产生 HTTP 错误400 Bad Request以及 JSON 错误响应:

{
  "error": {
    "code": 400,
    "message": "Request contains an invalid argument.",
    "errors": [
      {
        "message": "Request contains an invalid argument.",
        "domain": "global",
        "reason": "badRequest"
      }
    ],
    "status": "INVALID_ARGUMENT"
  }
}

Google 自己的问题跟踪器记录了一份最近的错误报告,该报告准确地描述了上述行为。谷歌工作人员的官方回应如下:

状态:无法修复(预期行为)

这是按预期工作的。基本上,如果是 for_content_owner 请求,您只能设置其中一个资源过滤器,但频道 ID 和发布后都是资源过滤器。开发者网站上似乎没有指定此要求:https ://developers.google.com/youtube/v3/docs/search/list 。


推荐阅读