【问题标题】:Retrieve all videos from youtube playlist using youtube v3 API使用 youtube v3 API 从 youtube 播放列表中检索所有视频
【发布时间】:2013-09-19 05:43:38
【问题描述】:

我正在使用 youtube v3 API 检索播放列表的视频,并通过此链接获取 50 个项目而没有任何问题:-

https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&maxResults=50&playlistId=PLB03EA9545DD188C3&key=MY_API_KEY

但是视频数是 100,而我只有 50 个。我怎样才能获得接下来的 50 个项目? 我试过 start-index 但它不适用于 v3 API。 任何帮助表示赞赏。

【问题讨论】:

标签: youtube youtube-api youtube-data-api


【解决方案1】:

YouTube Data API v3 结果是分页的。因此,您需要为其他人获取下一页结果。

基本上在你有nextPageToken的回复中。

要获得剩余的结果,请执行相同的调用,但将 pageToken 设置为您收到的令牌。

【讨论】:

【解决方案2】:

共有三个令牌

  1. 页面令牌
  2. nextPageToken
  3. prevPageToken

您也可以使用设置最大页面大小

maxResults=50 {允许的值 1 到 50 }

如果您在第 1 页,您将不会收到 prevPageToken

但你得到nextPageToken

将此令牌传递给下一个请求

pageToken = {nextPageToken 从上次请求中获取}

这样您就可以导航到下一页Try it Your Self

已编辑

好的,对于其他场景

如果你在首页,那么

  1. pageToken = '一些值'
  2. nextPageToken = '一些值'
  3. prevPageToken = null

如果你既不在第一页也不在最后一页,那么

  1. pageToken = '一些值'
  2. nextPageToken = '一些值'
  3. prevPageToken = '一些值'

@Manoj:你可以在下面找到你的答案

如果你在最后一页

  1. pageToken = '一些值'
  2. nextPageToken = null
  3. prevPageToken = '一些值'

甚至可能不存在该字段。

【讨论】:

  • 我们如何知道当前页是否是最后一页?上次响应中将缺少 nextPageToken
【解决方案3】:

这是一个使用 Python Youtube Client Lib 用 Python 制作的小例子 这也借鉴了 youtube API 示例中的样板设置

""" Pull All Youtube Videos from a Playlist """

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


DEVELOPER_KEY = "YOURKEY HERE"
YOUTUBE_API_SERVICE_NAME = "youtube"
YOUTUBE_API_VERSION = "v3"

def fetch_all_youtube_videos(playlistId):
    """
    Fetches a playlist of videos from youtube
    We splice the results together in no particular order

    Parameters:
        parm1 - (string) playlistId
    Returns:
        playListItem Dict
    """
    youtube = build(YOUTUBE_API_SERVICE_NAME,
                    YOUTUBE_API_VERSION,
                    developerKey=DEVELOPER_KEY)
    res = youtube.playlistItems().list(
    part="snippet",
    playlistId=playlistId,
    maxResults="50"
    ).execute()

    nextPageToken = res.get('nextPageToken')
    while ('nextPageToken' in res):
        nextPage = youtube.playlistItems().list(
        part="snippet",
        playlistId=playlistId,
        maxResults="50",
        pageToken=nextPageToken
        ).execute()
        res['items'] = res['items'] + nextPage['items']

        if 'nextPageToken' not in nextPage:
            res.pop('nextPageToken', None)
        else:
            nextPageToken = nextPage['nextPageToken']

    return res

if __name__ == '__main__':
  # comedy central playlist, has 332 video
  # https://www.youtube.com/watch?v=tJDLdxYKh3k&list=PLD7nPL1U-R5rDpeH95XsK0qwJHLTS3tNT
  videos = fetch_all_youtube_videos("PLD7nPL1U-R5rDpeH95XsK0qwJHLTS3tNT")

videos 将是连接到第一个列表的所有视频的列表。由于分页数为 50,它将继续获取所有视频。在其他语言中也可以采用类似的方法。

在列表中会有所有单独的视频元数据和顺序

【讨论】:

  • 我玩过一些我在 youtube API 页面上找到的 python 示例代码,也对您的代码有所启发。我希望将搜索关键字的所有结果写入文本文件。然而,我想知道写入文件中的结果总是小于 totalResults 数。也许你可以看看我的代码,看看为什么会这样?我真的很感激。这是我的代码:gist.github.com/amirteymuri/8b80ef813fa48c5a0703308041ec501d
  • 我的函数是find_vids
【解决方案4】:

youtube 发给我们的 JSON 数据中 data.pageInfo.totalResults 就是原来的视频总数。几个月或几年后,这个数字可能会因为视频删除、禁止而减少……实际上 youtube 只为我们提供当前可播放的视频。 因此,我们需要更改代码以获得更好的代码。
我们不应该使用 if(sum == data.pageInfo.toTalResults) 作为停止条件。 相反,让我们使用标准 if(typeof nextPageToken == ‘undefined’)。
在当前总数小于原始总数的情况下。如果我们使用旧编码,那么最后一个函数调用是使用未定义的 nextPageToken 进行的。这导致 Youtube 再次错误地给了我们第一个 JSON 页面。在结果中,我们有一些重复的视频。
请尝试我的新编码(看起来像 user3053204 先生给出的编码)

/* new coding. Please replace and use your api3 key */

function start(){
    count = 0; 
    $('#area1').val('');
    getVids();
}
function getVids(PageToken){
pid = $('#searchtext1').val();
$.get(
    "https://www.googleapis.com/youtube/v3/playlistItems",{
    part : 'snippet', 
    maxResults : 50,
    playlistId : pid,
    pageToken : PageToken,
    key: 'AIz....................................zm4'
    },
    function(data){
          myPlan(data);
    }        
    );  
}
count = 0;
str = '';

 function myPlan(data){
  nextPageToken=data.nextPageToken;
  pageLen = data.items.length;
  count += parseInt(pageLen);
  for(i=0; i<pageLen; i++){
           str += '"' + data.items[i].snippet.resourceId.videoId + '", ';
  }
   if(typeof nextPageToken == 'undefined'){
          total = data.pageInfo.totalResults;
          $('#all').html(count + '/' + total + ' videos');
          ind = str.lastIndexOf(',');
          str1 = str.substring(0, ind);
          $('#area1').val('arr = [' + str1 + '];\n');
          return;      
      }else{
          getVids(nextPageToken);
      }
 }

 <input type="text"  value="PLTI6yRvQqlYq9KoU-NHu43uDmKON7Fsjv" 
  id="searchtext1" size="75">&nbsp;
 <button onclick="start()">Get Items</button>
 <br><br>
 IDs for test: <br>
 <br>
 Ricky King playlist (92/103 videos):<br>
 PLTI6yRvQqlYq9KoU-NHu43uDmKON7Fsjv<br>
 Franck Pourcel playlist (425/425 videos):<br>
 PLMGmDo5xNOgU7gerHMwEk6SmD_vbPyLe9<br>
 Lobo playlist (25/41vids):<br>
 PLFE095732AC64AD06
 <br><br>         
 TOTAL:&nbsp;<span id="all"></span><br>
 <textarea id="area1" style="width:600px;height:500px;;font-size:12pt"></textarea>

/* old coding - to be cleared */

sum = 0;
sumN = 1;
var nextPageToken;

function getVids(PageToken){
    pid = $('#searchtext1').val();
    $.get(
        "https://www.googleapis.com/youtube/v3/playlistItems",{
        part : 'snippet', 
        maxResults : 50,
        playlistId : pid,
        pageToken : PageToken,
        key: 'YOUR API3 KEY'
        },
        function(data){
              myPlan(data);
        }        
    );  
 }

  function myPlan(data){
      total = data.pageInfo.totalResults;
      nextPageToken=data.nextPageToken;
      for(i=0;i<data.items.length;i++){
          document.getElementById('area1').value +=  
          sumN + '-' + data.items[i].snippet.title+'\n'+
          data.items[i].snippet.resourceId.videoId +'\n\n';
          sum++ ; sumN++;
          if(sum == (total-1) ){              
              sum = 0;  
              return;      
          }
      }  
      if(sum <(total-1)){
          getVids(nextPageToken);
      }    
 }
 
 function init(){
    $('#area1').val('');
 }
<!- - old coding - to be cleared - ->
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.js"></script>
  
  <body onload="$('#area1').val('')">
    
  <input type="text"  value="PLTI6yRvQqlYq9KoU-NHu43uDmKON7Fsjv" 
  id="searchtext1" size="75">&nbsp;
  <button onclick="getVids()">Get Items</button>
  <br><br>
  IDs for test: <br>PLTI6yRvQqlYq9KoU-NHu43uDmKON7Fsjv<br>
  PL32C69B40337EF920
  <br><br>         
  <textarea id="area1" style="width:600px;height:500px">
  </textarea>

【讨论】:

  • 我可以看到您从哪里获得您的密钥和播放列表 ID (pid),但是“PLTI6yRvQqlYq9KoU-NHu43uDmKON7Fsjv”来自哪里?这不是用户 ID、播放列表 ID、密钥或其他似乎特定于案例的因素,因为我已提取代码并使其正常工作,但我不知道这意味着什么
  • 抱歉回复晚了。最近我只使用 iPad 和使用 YouTube 应用程序。 1. 在 youtube 中,找到 PLTI6yRvQqlYq9KoU-NHu43uDmKON7Fsjv。您只会看到一个结果,即 Ricky King 器乐 103 视频。 2. 单击缩略图播放此播放列表。 3.如果你看到一个弯曲箭头形式的图标,点击它并选择复制链接,将会出现:youtube.com/watch?v=J0WKl7NaiHg&list=PLTI6yRvQqlYq9KoU-NHu43uDmKON7Fsjv
【解决方案5】:

获取所有视频的最简单方法,

DEVELOPER_KEY = "REPLACE_ME" YOUTUBE_API_SERVICE_NAME = "youtube" YOUTUBE_API_VERSION = "v3"

youtube = build("youtube", "v3", developerKey=api_key)
def get_videos_from_playlist(youtube, items, playlistID):
    response = items.list(part="snippet", playlistId=playlistID)
    while response:
        playlistitems_list_response = response.execute()

        for playlist_item in playlistitems_list_response["items"]:
            # title = playlist_item["snippet"]["title"]
            video_id = playlist_item["snippet"]["resourceId"]["videoId"]
            yield video_id

        response = youtube.playlistItems().list_next(
        response, playlistitems_list_response)

传递播放列表 ID,

items = youtube.playlistItems()
playlist = get_videos_from_playlist(youtube, items, 'PLoROMvodv4rOhcuXMZkNm7j3fVwBBY42z')

然后通过列表解析:

for videoID in playlist:
    print(videoID)

此外,您可以通过多个页面使用页面来抓取,例如:

nextPageToken = res.get('nextPageToken')
    while ('nextPageToken' in res):
        nextPage = youtube.playlistItems().list(
        part="snippet",
        playlistId=playlistId,
        maxResults="50",
        pageToken=nextPageToken
        ).execute()
        res['items'] = res['items'] + nextPage['items']

        if 'nextPageToken' not in nextPage:
            res.pop('nextPageToken', None)
        else:
            nextPageToken = nextPage['nextPageToken']

【讨论】:

    【解决方案6】:

    另一种解决方案,使用递归:

    $.fn.loadYoutubeResource = function(resource_request, resource_type, resource_id, resource_container, pageToken = null, callback = null){
        $.ajax({
                url: "https://www.googleapis.com/youtube/v3/" + resource_request,
                type: 'get',
                dataType: 'json',
                data: {
                        part : 'snippet', 
                        [resource_type]: resource_id,
                        maxResults : 50,
                        pageToken: pageToken,
                        key: '< API Key >', 
                      },
                success:    function(data) {
                                    console.log("New resource " + resource_type + " loaded:");
                                    console.log(data);                                          
                                    for(var index = 0; index < data.items.length; index++){                                         
                                        var url = data.items[index]['snippet'].thumbnails.default.url;
                                        var ytb_id = data.items[index]['id'];   
                                        jQuery('#' + resource_container).append('<img class="tube_thumbs" src="' + url + '" id="' + ytb_id 
                                                                            + '" title="' + data.items[index]['snippet']['title'] + '" >');
                                        }
                                    if ( data.nextPageToken == null)
                                        return callback();
                                    $.fn.loadYoutubeResource(resource_request, resource_type, resource_id, resource_container, data.nextPageToken, callback);                   
                            }
                });     
            }        
    

    然后调用如下:

    jQuery('body').append('<div id="ytb_container"></div>');
    
    $.fn.loadYoutubeResource('playlistItems', 'playlistId', 'PLmwK57OwOvYVdedKc_vPPfbcsey_R0K8r', 'ytb_container', null, function(){ <callback code>});
    

    【讨论】:

      【解决方案7】:

      这是我的递归函数,也许可以帮助某人:

      首先我为第一次通话创建了一个按钮:

      <button id="aux" class="btn btn-danger">Click Me</button>    
      

      然后在脚本部分:

         $(document).ready(function () {
      
              function getVideos(t) {
                  var url = "https://www.googleapis.com/youtube/v3/search?part=snippet&key=YourAPIKey&channelId=YourChannelID&maxResults=50";
                  if (t != undefined) {
                      url = url + "&pageToken=" + t
                  }
                  $.ajax({
                      type: 'GET',
                      url: url,
                      dataType: 'json',
                      success: function (html) {
                          console.log(html.items);
                          if (html.nextPageToken != undefined) {
                              getVideos(html.nextPageToken);
                          }
                      }
                  });
              };
      
              //initial call
              $("#aux").click(function () {
                  getVideos();
              });
       });
      

      问候

      【讨论】:

        【解决方案8】:

        另一种方法(无需知道请求格式并拥有 api 密钥):只需使用 youtube 播放列表 html 文件中的 json 并使用 JSON.parse 方法
        不幸的是,这种方法不能提供超过 200 个视频。在 json 中我看到了一些关键代码,可能是为了继续,但不能使用它们。
        要获取 html 源代码,我们可以使用 jquery $.ajax 方法。

        <meta charset = utf-8>
        <body>
        <div id="help" style="width:90%">
        1- Open youtube.com and search for playlist   (http://www.youtube.com/....&list=...)<br>
        For example: click <a href="http://www.youtube.com/watch?v=sMyj9e2qOc0&list=PL33196EF7664597D5">paul mauriat playlist</a><br>
        You will see in the adress bar: http://www.youtube.com/watch?v=sMyj9e2qOc0&list=PL33196EF7664597D5 <br>
        Select all and copy this url.<br>
        2- Open any online html source code  viewer. For example<br>
        <a href="https://www.duplichecker.com/page-snooper.php">
        https://www.duplichecker.com/page-snooper.php</a><br>
        Paste the url, click "Enter", wait several seconds, scroll down, click   "Copy"<br>
        3- Return to this page. Paste the code to the below input smal textarea, wait several seconds, click "GET VIDEO IDS".<br>
        4- Click the button TEST JAVASCRIPT.
        </div><br>
        <textarea id = "input">
        </textarea><br>
        <button onclick="extract()">GET VIDEOS IDS</button><br>
        Total:&nbsp;<span id='len'></span>
        <br><button onclick="test()">TEST JAVASCRIPT</button><br>
        COPY THIS TO CREATE A JAVASCRIPT FILE<br>
        <textarea id="area2" style="width:90%;height:400px;font-size:14pt">
        </textarea><br>
        
        <script> 
        function extract(){
        str = document.getElementById('input').value;
        aa = str.indexOf('{"responseContext');
        bb = str.indexOf('{"related', aa);
        jsn = str.substring(aa, bb + 24);
        obje = JSON.parse(jsn);
        alert('Click OK to continue');
        make();
        }
        glStr = '';
        function make(){
        len = obje.contents.singleColumnWatchNextResults.playlist.playlist.contents.length;
        ss = '';
        for(i=0; i < len; i++){
        try{
           ti = obje.contents.singleColumnWatchNextResults.playlist.playlist.contents[i].playlistPanelVideoRenderer.title.runs[0].text;
           ti1 = ti.replace(/"/g,'\\"');
           ide = obje.contents.singleColumnWatchNextResults.playlist.playlist.contents[i].playlistPanelVideoRenderer.navigationEndpoint.watchEndpoint.videoId;
            }catch(e){
                        ide = obje.contents.singleColumnWatchNextResults.playlist.playlist.contents[i].playlistPanelVideoRenderer.videoId;
                        ti1 = '[Deleted Video]';
        }
            ss += '{vid:"' + ide + '",tit:"' + ti1 + '"}';
            if(i != (len - 1)){
                ss += ',\n';
            }
        } 
        glStr = 'obj = \n[' + ss + '\n];\n';
        document.getElementById('area2').value = glStr;
        document.getElementById('len').innerHTML = len + ' videos';
        }
        function test(){
        var head = document.getElementsByTagName('head').item(0);
        var script = document.createElement('script');
        script.setAttribute('type', 'text/javascript');
        script.innerHTML = glStr;
        head.appendChild(script);
         alert('obj.length = ' + obj.length);
         alert('obj[5].vid = ' + obj[5].vid + '\n obj[5].tit = ' +   obj[5].tit);
        }
        </script>
        </body>
        

        【讨论】:

          【解决方案9】:

          我做了如下,但我不知道这个是优化的还是没有任何我如何得到我预期的结果。

          解释: 将从播放列表中检索所有视频并动态推送到一个数组中。

          服务中:

              getSnippets(token): any {
              console.log('API_TOKEN:',token);
              if(token){
                return this.http.get('https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=PLV_aspERmuCKxUPxu8UwUd3I52VLje0ra&maxResults=100&key=[API_KEY]='+token).toPromise();
              }else{
                return this.http.get('https://www.googleapis.com/youtube/v3/playlistItems?part=snippet&playlistId=PLV_aspERmuCKxUPxu8UwUd3I52VLje0ra&maxResults=100&key=[API_KEY]').toPromise();
              }
            }
          

          显示数据:

                async getPlayList(){
              try{
                let pageToken;
                this.finalAr = [];
                // for(let t = 0; t <= 1; t++) {
                  const list = await this.service.getSnippets(pageToken);
                  pageToken          = list.nextPageToken;
                  // let pageInfo       = list.pageInfo;
                  let pageTot        = list.pageInfo.totalResults;
                  let resultsPerPage = list.pageInfo.resultsPerPage;
                  let loopCnt        = pageTot / resultsPerPage;
                  let finalCnt       = Math.abs(Math.ceil(loopCnt)) - 1 ;
                  if(pageToken != undefined || pageToken != null){
                    let tempAr   = list.items;        
                    for(let i = 0; i < tempAr.length; i++){
                      this.finalAr.push({"vid_id"   : tempAr[i].snippet.resourceId.videoId,
                                         "vid_title": tempAr[i].snippet.title,
                                         "vid_desc" : tempAr[i].snippet.description,
                                         "vid_icon" : 'https://i.ytimg.com/vi/'+tempAr[i].snippet.resourceId.videoId+'/sddefault.jpg'
                                        })
                    }
                    console.log('finalAr_1:',this.finalAr);
                  }
                  for(let a = 1; a <= finalCnt; a++){
                    const listF = await this.service.getSnippets(pageToken);
                      pageToken = listF.nextPageToken;
                      let tempAr   = listF.items;      
                      for(let i = 0; i < tempAr.length; i++){
                        this.finalAr.push({"vid_id"   : tempAr[i].snippet.resourceId.videoId,
                                           "vid_title": tempAr[i].snippet.title,
                                           "vid_desc" : tempAr[i].snippet.description,
                                           "vid_icon" : 'https://i.ytimg.com/vi/'+tempAr[i].snippet.resourceId.videoId+'/sddefault.jpg'
                                          })
                      }
                      console.log('finalAr_2:',this.finalAr);
                  }
              }catch (e){
                console.log('ER:',e);
              }
          

          完成了任务。但如果有人知道这件事,我想从多个播放列表中检索所有视频,请告诉我。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2015-08-20
            • 1970-01-01
            • 2013-03-18
            • 2015-08-19
            • 2018-06-11
            • 1970-01-01
            • 2016-06-15
            • 2017-06-25
            相关资源
            最近更新 更多