0

So I have been working on putting together a database based on a bunch of APIs I imported (over 20,000), so no custom IMPORTAPI functions have had enough abilities to extract the information from the data, so I have been working on a script to collect that data in an array, then import it all at once so I'm not constantly appending rows, which I have gotten to work, but is too slow to get through the whole list. Here is the current code I have put together in my attempts to make this work:

function dataImport() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Import1");
  var countRow = 1;
  var exportSheet = ss.getSheetByName("Data1");
  var url = sheet.getRange("A2:A").getRichTextValue().getLinkUrl();
  var playerCount = sheet.getRange("A2:A").getValues().filter(String).length

  var response = UrlFetchApp.fetch(url);
  var data = response.getContentText();
  var playerResult = JSON.parse(data);

  var id = playerResult.id
  var firstName = playerResult.firstName
  var lastName = playerResult.lastName
  var fullName = playerResult.fullName
  var displayName = playerResult.displayName
  var shortName = playerResult.shortName
  var weight = playerResult.weight;
    if (weight.error){
      return null
    }
  var height = playerResult.height;
    if (height.error){
      return null
    }  
  var position = playerResult.position.abbreviation;
    if (position.error){
      return null
    }      
  var teamUrl = playerResult.team.$ref;
    if (teamUrl.error){
      return null
    }  
  var city = playerResult.birthPlace.city;
    if (city.error){
      return null
    }  
  var state = playerResult.birthPlace.state;
    if (state.error){
      return null
    }  
  var country = playerResult.birthPlace.country;
    if (country.error){
      return null
    }  
  var years = playerResult.experience.years;
    if (years.error){
      return null
    }  
  var displayClass = playerResult.experience.displayValue;
    if (displayClass.error){
      return null
    }  
  var jersey = playerResult.jersey;
    if (jersey.error){
      return null
    }  
  var active = playerResult.active 

  var { items, playerCount } = playerResult;
  items = items.map(e => [e[id,firstName,lastName,fullName,displayName,shortName,weight,height,position,teamUrl,city,state,country,years,displayClass,jersey,active]])
  var reqs = []
  for (var p = 1; p <= playerCount; p++) {
    reqs.push(url + p)
  }
  var responses = UrlFetchApp.fetchAll(reqs);
  var temp = responses.flatMap(r => r.getResponseCode() == 200 ? JSON.parse(r.getContentText()).items.map(e => [e[id,firstName,lastName,fullName,displayName,shortName,weight,height,position,teamUrl,city,state,country,years,displayClass,jersey,active]]) : []);
  var res = [['IDs','First Name','Last Name','Full Name','Display Name','Short Name','Weight','Height','Position','Team URL','City','State','Country','Years','Class','Active'], ...items, ...temp];
  exportSheet.getRange(countRow, 1, res.length).setValues(res);
}

Now there may be other issues with this function I have not been able to find yet, but I'm running into an error saying "TypeError: Cannot read properties of undefined (reading 'map')", and I'm not exactly sure how to fix it. There may be other issues with this code as I have not been able to get an import to work due to this error, such as my makeshift IFERROR work with variables like "weight" that do not show up in every API link. I'm not completely sure if I have the looping mechanism right to go through all of the links in the cells or not. If I can get any help with this, I would appreciate it; I also have provided a list of test links from my sheet so testing can be done with getting the data. The sheet it pulls from is very simple, with a header row in A1, then links in every column below it.

http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/4921396?lang=en&region=us ,

http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/5081996?lang=en&region=us ,

http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/5154876?lang=en&region=us ,

http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/5156268?lang=en&region=us ,

http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/4694036?lang=en&region=us ,

http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/5087348?lang=en&region=us ,

http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/5096914?lang=en&region=us ,

http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/5091329?lang=en&region=us ,

http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/4838673?lang=en&region=us ,

http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/5042882?lang=en&region=us

DJ Luke
  • 31
  • 6
  • If your showing URLs are actually used to column "A" of "Import1" sheet, `url` of `var url = sheet.getRange("A2:A").getRichTextValue().getLinkUrl();` the column "A2". If that is `http://sports.core.api.espn.com/v2/sports/football/leagues/college-football/athletes/4921396?lang=en®ion=us`, unfortunately, it seems that the retrieved value doesn't include the properties of `items, playerCount`. If my understanding is correct, I think that this is the reason for your current issue of `TypeError: Cannot read property of unknown (reading 'map')`. In this case, what result do you want to retrieve? – Tanaike Aug 14 '23 at 01:49
  • I guess I missed that one; what I'm looking to import is the same as what is in the map piece of the formula (id,firstName,lastName,fullName,displayName,shortName,weight,height,position,teamUrl,city,state,country,years,displayClass,jersey,active) – DJ Luke Aug 14 '23 at 02:11
  • Thank you for replying. From your reply, I proposed a sample script as an answer. Please confirm it. If that was not useful, I apologize. – Tanaike Aug 14 '23 at 03:08

1 Answers1

1

From your following reply,

I guess I missed that one; what I'm looking to import is the same as what is in the map piece of the formula (id,firstName,lastName,fullName,displayName,shortName,weight,height,position,teamUrl,city,state,country,years,displayClass,jersey,active)

I understood that you have wanted to retrieve the values of id,firstName,lastName,fullName,displayName,shortName,weight,height,position,teamUrl,city,state,country,years,displayClass,jersey,active from each URL.

In your current script, unfortunately, this cannot be achieved. In order to achieve your goal, how about the following sample script?

Sample script:

function dataImport() {
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = ss.getSheetByName("Import1");
  var countRow = 1;
  var exportSheet = ss.getSheetByName("Data1");
  var reqs = sheet.getRange("A2:A" + sheet.getLastRow()).getDisplayValues().reduce((ar, [url]) => {
    if (url) {
      ar.push({ url, muteHttpExceptions: true });
    }
    return ar;
  }, []);
  // Or, please use the following script for retrieving the URLs from column "A". 
  // var reqs = sheet.getRange("A2:A" + sheet.getLastRow()).getRichTextValues().reduce((ar, [a]) => {
  //   if (a && a.getLinkUrl()) {
  //     ar.push({ url: a.getLinkUrl(), muteHttpExceptions: true });
  //   }
  //   return ar;
  // }, []);

  var responses = UrlFetchApp.fetchAll(reqs);
  var temp = responses.reduce((ar, r) => {
    if (r.getResponseCode() == 200) {
      var { id, firstName, lastName, fullName, displayName, shortName, weight, height, position: { abbreviation }, team: { $ref }, birthPlace: { city }, birthPlace: { state, country }, experience: { years, displayValue }, jersey, active } = JSON.parse(r.getContentText());
      ar.push([id, firstName, lastName, fullName, displayName, shortName, weight, height, abbreviation, $ref, city, state, country, years, displayValue, jersey, active]);
    }
    return ar;
  }, []);
  var res = [['IDs', 'First Name', 'Last Name', 'Full Name', 'Display Name', 'Short Name', 'Weight', 'Height', 'Position', 'Team URL', 'City', 'State', 'Country', 'Years', 'Class', 'jersey', 'Active'], ...temp];
  exportSheet.getRange(countRow, 1, res.length, res[0].length).setValues(res);
}

Testing:

When this sample script is run using your showing URLs, the following result is obtained.

enter image description here

Note:

  • About over 20,000, I'm worried that this sample script can be directly used for your actual situation. If an error related to the concurrent HTTP requests occurs, it might be required to split the URLs. Or UrlFetchApp.fetch might be suitable instead of UrlFetchApp.fetchAll.

References:

Tanaike
  • 181,128
  • 11
  • 97
  • 165
  • Thank you @Tanaike for your response! So I tried the code and did end up getting this error, "Exception: Service invoked too many times in a short time: urlfetch. Try Utilities.sleep(1000) between calls." The most successful attempt I got was getting a different error after placing the sleep command after the fetch, saying "Exception: Service Spreadsheets failed while accessing document with id 18tRBBcVwChuSJ0G5_A09I7EoQnji6nmRvOWcX5ndALE." To the next comment, I'll attach a copy of the full list of links if you would be willing to try and see what you can do for the large quantity – DJ Luke Aug 14 '23 at 06:47
  • Here is that link with all of the data: https://docs.google.com/spreadsheets/d/1Nmjw7wCv5FzBFIE8QfqHOYGPioIkv79InBsJzpmEnyw/edit?usp=sharing – DJ Luke Aug 14 '23 at 06:49
  • @DJ Luke Thank you for replying. Your reply is the same as my concern. But, in this case, I would like to propose separating your question between your showing URLs in your question and your actual situation. Because my answer is for your showing URLs. When you tested my script using your showing URLs, what result did you obtain? If that worked, I would like to propose you post your new issue as a new question. By this, your questions will be also useful for other users. If you can cooperate to resolve your new issue, I'm glad. Can you cooperate to do it? – Tanaike Aug 14 '23 at 08:41
  • @DJ Luke When I saw your Spreadsheet, it seems that 27866 URLs are existing. In this case, I'm worried that even when the URLs are split, the process cannot be finished in one execution (6 minutes). So, I think that it is required to use another process. For example, those are the time-driven triggers and Javascript instead of Google Apps Script. From this situation, I would like to propose posting your new issue as a new question. I would like to support you. By the way, first, can you confirm whether my sample script works using your 10 URLs? – Tanaike Aug 14 '23 at 10:14
  • I just test with 10 URLs and it does work exactly as intended so thank you for that! I'll try what you are saying about posting a separate question for the large quantity of URLs, and hope that can be fixed that way. Thank you again. – DJ Luke Aug 14 '23 at 20:08
  • Here is the link to the new question I posted based on the quantity issue, thank you again! [Import of a Large Quantity of API Data Through Apps Script] (https://stackoverflow.com/questions/76901959/import-of-a-large-quanity-of-api-data-through-apps-script?noredirect=1#comment135570780_76901959) – DJ Luke Aug 14 '23 at 23:00