Workaround for Retrieving Direct Links of All Sheets from URL of 2PACX- of Web Published Google Spreadsheet

Gists

This is a sample script for retrieving the direct links of all sheets from the URL like https://docs.google.com/spreadsheets/d/e/2PACX-###/pubhtml of the web published Google Spreadsheet. This sample script can be used for the following situation.

  1. The Spreadsheet is published to Web and the URL like https://docs.google.com/spreadsheets/d/e/2PACX-###/pubhtml is known
  2. You are not the owner of Google Spreadsheet.
  3. You don’t know the Spreadsheet ID and Sheet IDs.

Under above situation, unfortunately, the direct links of each sheet cannot be directly retrieved. I think that this is the specification of Google side. So in this post, I would like to introduce a workaround for retrieving the direct links of each sheet under above situation.

Flow

The flow of this workaround is as follows.

  1. Download the Google Spreadsheet as a XLSX data from the URL of https://docs.google.com/spreadsheets/d/e/2PACX-###/pubhtml.
  2. Convert the XLSX data to Google Spreadsheet.
  3. Publish the converted Google Spreadsheet to Web.
  4. Retrieve the URLs of each sheet.

Sample script 1

Please copy and paste the following script (Google Apps Script) to the script editor. And please enable Google Drive API at Advanced Google services. This script is for the Web Apps.

function myFunction() {
  const inputUrl = "https://docs.google.com/spreadsheets/d/e/2PACX-###/pubhtml";

  const prop = PropertiesService.getScriptProperties();
  const ssId = prop.getProperty("ssId");
  if (ssId) {
    DriveApp.getFileById(ssId).setTrashed(true);
    prop.deleteProperty("ssId");
  }
  const re = new RegExp(
    "(https?:\\/\\/docs\\.google\\.com\\/spreadsheets\\/d\\/e\\/2PACX-.+?\\/)"
  );
  if (!re.test(inputUrl)) throw new Error("Wrong URL.");
  const url = `${inputUrl.match(re)[1]}pub?output=xlsx`;
  const blob = UrlFetchApp.fetch(url).getBlob();
  const id = Drive.Files.insert(
    { mimeType: MimeType.GOOGLE_SHEETS, title: "temp" },
    blob
  ).id;
  prop.setProperty("ssId", id);
  Drive.Revisions.update(
    { published: true, publishedOutsideDomain: true, publishAuto: true },
    id,
    1
  );
  const sheets = SpreadsheetApp.openById(id).getSheets();
  const pubUrls = sheets.map((s) => ({
    [s.getSheetName()]: `https://docs.google.com/spreadsheets/d/${id}/pubhtml?gid=${s.getSheetId()}`,
  }));
  console.log(pubUrls);
}

Sample script 2

Please copy and paste the following script (Google Apps Script) to the script editor. And please enable Google Drive API v2 at Advanced Google services. This script is for the Web Apps.

As another workaround, when the original Spreadsheet is often changed, and the number of sheet is constant in the original Spreadsheet, and then, you want to retrieve only values, you can also use the following script. In this script, the URL is not changed even when the script is run again. So you can continue to use the URL. And, when this function is run using the time-driven trigger, you can also synchronize with the original Spreadsheet.

function myFunction() {
  const inputUrl = "https://docs.google.com/spreadsheets/d/e/2PACX-###/pubhtml";
  
  const re = new RegExp("(https?:\\/\\/docs\\.google\\.com\\/spreadsheets\\/d\\/e\\/2PACX-.+?\\/)");
  if (!re.test(inputUrl)) throw new Error("Wrong URL.");
  const url = `${inputUrl.match(re)[1]}pub?output=xlsx`;
  const blob = UrlFetchApp.fetch(url).getBlob();
  const prop = PropertiesService.getScriptProperties();
  let sheets;
  let ssId = prop.getProperty("ssId");
  if (ssId) {
    const temp = Drive.Files.insert({mimeType: MimeType.GOOGLE_SHEETS, title: "tempSpreadsheet"}, blob).id;
    const tempSheets = SpreadsheetApp.openById(temp).getSheets();
    sheets = SpreadsheetApp.openById(ssId).getSheets();
    tempSheets.forEach((e, i) => {
      const values = e.getDataRange().getValues();
      sheets[i].getRange(1, 1, values.length, values[0].length).setValues(values);
    });
    DriveApp.getFileById(temp).setTrashed(true);
  } else {
    ssId = Drive.Files.insert({mimeType: MimeType.GOOGLE_SHEETS, title: "copiedSpreadsheet"}, blob).id;
    Drive.Revisions.update({published: true, publishedOutsideDomain: true, publishAuto: true}, ssId, 1);
    prop.setProperty("ssId", ssId);
    sheets = SpreadsheetApp.openById(ssId).getSheets();
  }
  const pubUrls = sheets.map(s => ({[s.getSheetName()]: `https://docs.google.com/spreadsheets/d/${ssId}/pubhtml?gid=${s.getSheetId()}`}));
  console.log(pubUrls);  // You can see the URLs for each sheet at the log.
}

Testing

References

 Share!