概要
Google は goo.gl 短縮 URL サービスを終了することを発表しました。その後一部変更され、使用頻度の低い URL は削除、使用頻度の高い URL は継続されることになりました。
私が昔使っていた Google SpreadSheet の中には goo.gl 短縮 URL が沢山あります。サービス縮小までに元の URL に置換する必要がでてきました。
何をする?
- http://goo.gl または https://goo.gl から始まる文字列を含むセルを探す
- リダイレクト先 URL を取得する
- ただし「もうじきこのURLは使えなくなるよ」の画面へリダイレクトされる場合がある
- この場合はリダイレクト先URLも https://goo.gl になる
- リダイレクト先も https://goo.gl だった場合はソースコードの中から redirect-url="https://*" を探して URL を取得する
免責事項
ここから下に実際のソースコードがあります。
- 何が起こっても知りません。自己責任で使用してください。
- 実行する前にスプレッドシートをコピー(複製)することを強くお勧めします。
- 転送先URLの事情によりもう一度リダイレクトされる場合はうまく取得できません。
ソースコード
ChatGPT と試行錯誤してまともに動くようになったコードがこれです。
Google Apps Script
function expandAllGooGlUrlsInSpreadsheet() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheets = ss.getSheets();
const maxRedirect = 3;
sheets.forEach(sheet => {
const range = sheet.getDataRange();
const values = range.getValues();
let updated = false;
for (let i = 0; i < values.length; i++) {
for (let j = 0; j < values[i].length; j++) {
const cell = values[i][j];
if (typeof cell === 'string' && /https?:\/\/goo\.gl/.test(cell)) {
// セル内のgoo.gl URLを全部探す
const urls = extractGooGlUrls(cell);
let newCell = cell;
urls.forEach(shortUrl => {
try {
const expandedUrl = expandUrlWithRedirectHandling(shortUrl, maxRedirect);
if (expandedUrl && expandedUrl !== shortUrl) {
newCell = newCell.replace(shortUrl, expandedUrl);
}
} catch (e) {
Logger.log('Error expanding URL: ' + shortUrl + ' - ' + e.message);
}
});
if (newCell !== cell) {
values[i][j] = newCell;
updated = true;
}
}
}
}
if (updated) {
range.setValues(values);
}
});
}
/**
* セルの文字列から http://goo.gl で始まるURLを全部抽出
* @param {string} text
* @returns {string[]}
*/
function extractGooGlUrls(text) {
const regex = /https?:\/\/goo\.gl\/[A-Za-z0-9]+/g;
const matches = text.match(regex);
return matches ? matches : [];
}
/**
* 短縮URLを展開し、条件に応じて data-redirect-url を探す
* @param {string} url
* @param {number} maxRedirect
* @returns {string} 最終的な展開先URL
*/
function expandUrlWithRedirectHandling(url, maxRedirect) {
let currentUrl = url;
for (let i = 0; i < maxRedirect; i++) {
const response = UrlFetchApp.fetch(currentUrl, { muteHttpExceptions: true, followRedirects: false });
const code = response.getResponseCode();
if (code >= 300 && code < 400) {
// リダイレクト先URLを取得
let location = response.getHeaders()['Location'] || response.getHeaders()['location'];
if (!location) {
throw new Error('Redirect location header not found for URL: ' + currentUrl);
}
// URLが相対パスの場合は絶対パスに変換
location = toAbsoluteUrl(currentUrl, location);
if (location.includes('goo.gl')) {
// goo.gl ドメインならHTMLの data-redirect-url を抽出する
const htmlResponse = UrlFetchApp.fetch(location, { muteHttpExceptions: true });
const html = htmlResponse.getContentText();
const redirectUrl = extractDataRedirectUrl(html);
if (redirectUrl) {
currentUrl = redirectUrl;
// これで終わらずに次のループで展開を続ける
} else {
currentUrl = location;
}
} else {
currentUrl = location;
}
} else {
// リダイレクトではない場合は終わり
break;
}
}
return currentUrl;
}
/**
* 相対パスのLocationを絶対URLに変換
* @param {string} baseUrl
* @param {string} location
* @returns {string}
*/
function toAbsoluteUrl(baseUrl, location) {
if (/^https?:\/\//.test(location)) {
return location;
}
// baseUrlのドメイン部分を抽出
const urlObj = new URL(baseUrl);
if (location.startsWith('/')) {
return urlObj.protocol + '//' + urlObj.host + location;
} else {
// 相対パスのケース
const path = urlObj.pathname.split('/');
path.pop(); // 最後のファイル名を除く
const newPath = path.join('/') + '/' + location;
return urlObj.protocol + '//' + urlObj.host + newPath;
}
}
/**
* HTMLソースから data-redirect-url="..." を抽出
* @param {string} html
* @returns {string|null}
*/
function extractDataRedirectUrl(html) {
const regex = /data-redirect-url="([^"]+)"/;
const match = html.match(regex);
return match ? match[1] : null;
}
使い方
- Google スプレッドシートを開く
- 拡張機能 → Apps Script を開く
- 上記コードを貼り付ける
- 保存する( Ctrl + S またはフロッピーディスクのボタンをクリック)
- expandAllGooGlUrlsInSpreadsheet を実行
- 初回は「権限承認」が求められるので許可する
- シート内の goo.gl URL が元URLに置き換わる
関連リンク