Search code examples
google-apps-scriptgoogle-sheetsyoutube-apigoogle-apis-explorer

How do I scrape the subscriberCount from Youtube API through apps script on Google Sheets?


This what I have so far:

function YoutubeScraper() {
  var spreadSheet = SpreadsheetApp.getActiveSpreadsheet()
  var activeSheet = spreadSheet.getActiveSheet()
  var search = YouTube.Search.list("snippet, id", {q: "pizza", maxResults: 50})
  var results = search.items.map((item) => [item.id.videoId, item.snippet.title, item.snippet.publishedAt, item.snippet.thumbnails.default.url])
  var ids = results.map((id) => id[0]).join(",")
  var stats = YouTube.Videos.list("statistics", {id: ids})
  var videoStats = stats.items.map((item) => [item.statistics.viewCount, item.statistics.likeCount, item.statistics.dislikeCount])
  activeSheet.getRange(2,1,results.length, results[0].length).setValues(results)
  activeSheet.getRange(2,3, videoStats.length, results[0].length).setValues(videoStats)
}

I tried adding item.statistics.subscriberCount in

var videoStats = stats.items.map((item) => [item.statistics.viewCount, item.statistics.likeCount, item.statistics.dislikeCount])

but it does not work. There's a note on https://developers.google.com/youtube/v3/docs/channels/list#common-use-cases that says that " statistics.subscriberCount property value has been updated to reflect a YouTube policy change that affects the way that subscriber counts are displayed". What can I do to get the subscriberCount? The output should be a data


Solution

  • Modification points:

    • I thought that in your situation, in order to retrieve the value of subscriberCount, the method of "Channels: list" will be used like YouTube.Channels.list. Also, your provided URL of official document is for the method of "Channels: list".
    • But in your script, YouTube.Videos.list is used. I thought that this might be the reason fo your issue.
    • In your script, I thought that you wanted to put the values of subscriberCount to the same row of the channel ID. But, in your current script, results has 4 columns. But videoStats is put from the column "C". In this case, the columns "C" and "D" are overwritten.

    When above points are reflected to your script, it becomes as follows.

    Modified script:

    function YoutubeScraper() {
      var spreadSheet = SpreadsheetApp.getActiveSpreadsheet()
      var activeSheet = spreadSheet.getActiveSheet();
      var search = YouTube.Search.list("snippet", { q: "pizza", maxResults: 50 });
      var results = search.items.map((item) => [item.snippet.channelId, item.snippet.title, item.snippet.publishedAt, item.snippet.thumbnails.default.url]);
      var ids = results.map((id) => id[0]).join(",");
      var stats = YouTube.Channels.list("statistics", { id: ids });
      var videoStats = stats.items.map((item) => [item.id, item.statistics.viewCount, item.statistics.subscriberCount]).reduce((o, [id, ...v]) => Object.assign(o, {[id]: v}));
      results = results.map(e => videoStats[e[0]] ? e.concat(videoStats[e[0]]) : e.concat(Array(2).fill("")));
      activeSheet.getRange(2, 1, results.length, results[0].length).setValues(results);
    }
    
    • In this modification, the values of videoStats are converted to an object for searching the channel ID. And, using the object, each value is pushed to the corresponding row of results. And then, the values are put to the active sheet.
    • At YouTube.Channels.list, there are no properties of item.statistics.likeCount, item.statistics.dislikeCount.

    Reference:

    Added:

    From your following replying,

    that issue has not been completely resolved. What I am trying to do is to get all the information I can, from YouTube.Seach: channelId, videoId, title of the video, when it was published and the thumbnail. From YouTube.Videos: the number of likes, dislikes views and comments. From YouTube.Channels: the overall number of views of the channels and the number of subscribers How about the following modified script?

    Modified script:

    function YoutubeScraper2() {
      var spreadSheet = SpreadsheetApp.getActiveSpreadsheet()
      var activeSheet = spreadSheet.getActiveSheet();
    
      // Retrieve YouTube.Search.list.
      var search = YouTube.Search.list("snippet", { q: "pizza", maxResults: 50 });
      var results = search.items.map((item) => [item.snippet.channelId, item.id.videoId, item.snippet.title, item.snippet.publishedAt, item.snippet.thumbnails.default.url]);
      
      // Retrieve channel IDs and video IDs.
      var {channelIds, videoIds} = results.reduce((o, [channelId, videoId]) => {
        o.channelIds.push(channelId);
        o.videoIds.push(videoId);
        return o;
      }, {channelIds: [], videoIds: []});
    
      // Retrieve YouTube.Videos.list.
      var videoList = YouTube.Videos.list("statistics", {id: videoIds.join(",")});
      var videoStats = videoList.items.map((item) => [item.id, item.statistics.viewCount, item.statistics.likeCount, item.statistics.dislikeCount]).reduce((o, [id, ...v]) => Object.assign(o, {[id]: v}), {});
    
      // Retrieve YouTube.Channels.list
      var channelList = YouTube.Channels.list("statistics", { id: channelIds.join(",") });
      var channelStats = channelList.items.map((item) => [item.id, item.statistics.viewCount, item.statistics.subscriberCount]).reduce((o, [id, ...v]) => Object.assign(o, {[id]: v}), {});
    
      // Create an array for putting values and put the values to Spreadsheet.
      results = results.map(e => channelStats[e[0]] ? e.concat(channelStats[e[0]]) : e.concat(Array(2).fill("")));
      results = results.map(e => videoStats[e[1]] ? e.concat(videoStats[e[1]]) : e.concat(Array(3).fill("")));
      var header = ["channelId", "videoId", "title", "publishedAt", "thumbnails", "viewCount", "subscriberCount", "viewCount", "likeCount", "dislikeCount"];
      results.unshift(header);
      activeSheet.getRange(1, 1, results.length, results[0].length).setValues(results);
    }
    
    • When above script is run, the columns channelId, videoId, title, publishedAt, thumbnails, viewCount, subscriberCount, viewCount, likeCount, dislikeCount are put to the active sheet.
    • If you don't want to put the header, please modify the last 3 lines to activeSheet.getRange(2, 1, results.length, results[0].length).setValues(results);.
    • If you want to arrange the columns, please modify above script.

    Result:

    When above script is run, the following Spreadsheet is obtained.

    enter image description here