mohiro0714
@mohiro0714

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

GASを使用してスプレッドシート内のURLから短縮URLとQRコード作成

解決したいこと

Googleドライブ内のフォルダ(元画像)に入っている画像のURLを取得し、
X.gdのAPIを使用して短縮URLに変換。
その後QR code APIを使用して短縮URLからQRコードを作成するGASを作成しました。

先に短縮URLをスプレッドシート内のセルの値に入力し、その値を読み取ってから
QRコード作成をしているつもりなのですが、先にQRコードを作成しようとするため
読み取っても値が空のQRコードが作成されてしまいます。

先に作成している(はずの)短縮URLの値をQR code APIに渡すにはどこを見直したら
よろしいですか。

該当するソースコード

// 初期設定
// 元画像が入っているフォルダIDを入力
  var oldFolderID = 'ここに入力';
  var oldFolder = DriveApp.getFolderById(oldFolderID);
// 作成されたQRコードを出力するフォルダIDを入力
  var QRFolderID = 'ここに入力';
  var QRFolder = DriveApp.getFolderById(QRFolderID);
// X.gdのAPIから短縮URLを作成するためのAPIキーを入力
  var apiKey = 'ここに入力';
// 初期設定ここまで

function makeQR_shortenURL() {
// 元画像フォルダ内のファイル名とURLを取得して、スプシに出力させる
// スプレッドシートとシートの指定
  var activeSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = activeSpreadSheet.getSheetByName('QRコード作成用'); // 必要に応じて変更します
// シートをクリア
sheet.clear();
// シートのタイトル行を設定
sheet.appendRow(['', 'ファイル名', '拡張子なし', 'GoogleドライブでのURL', '短縮URL']);

// フォルダ内のファイルを取得
  var files = oldFolder.getFiles();

// ファイル名、拡張子なし、Googleドライブ上のURL、短縮URLを変数に代入
  while (files.hasNext()) {
    var file = files.next();
    var fileName = file.getName();
    var kakuNashi = fileName.substring(0, fileName.length -4);
    var fileUrl = file.getUrl();
    var shortURL = shortenUrlWithXgd(fileUrl, apiKey);
    // ファイル名、拡張子なし、Googleドライブ上のURL、短縮URLをスプシに出力
      sheet.appendRow([, fileName, kakuNashi, fileUrl, shortURL]);
  }
}

// Googleドライブ上のURLから短縮URLを作成
// スプシから元のURLを取得して短縮URLを出力
  var activeSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = activeSpreadSheet.getSheetByName('QRコード作成用'); // 必要に応じて変更します
  var lastRow = sheet.getLastRow();
    for (var i = 2; i <= lastRow; i++) {
    // 元のURLがD列に入っている場合
      var longUrl = sheet.getRange(i, 4).getValue();
    // E列に既に短縮URLがあるか確認
      var existingShortUrl = sheet.getRange(i, 5).getValue();
    // E列が空で、D列にURLがある場合のみ短縮URLを生成
      if (longUrl && !existingShortUrl) {
        var shortUrl = shortenUrlWithXgd(longUrl, apiKey);
      // E列に短縮URLを表示
        sheet.getRange(i, 5).setValue(shortUrl); 
    }
  }

function shortenUrlWithXgd(longUrl, apiKey) {
// X.gdのAPIを使用するためのurl設定
  var url = "https://xgd.io/V1/shorten?url=" + encodeURIComponent(longUrl) + "&key=" + apiKey; 
  var options = {
  method: "GET",
  muteHttpExceptions: true
};
  var response = UrlFetchApp.fetch(url, options);
//短縮化するURLが多いとサーバーの処理が間に合わないため1000ms待ってから
  Utilities.sleep(1000);
// 正常に処理が行われなかった場合
  if (response.getResponseCode() !== 200) {
    Logger.log("Error: " + response.getContentText());
    throw new Error("Failed to shorten URL. Status code: " + response.getResponseCode());
  }
    
  var data = JSON.parse(response.getContentText());
    Logger.log("Shortened URL: " + data.shorturl); // 短縮URLをログに出力
  return data.shorturl; // 短縮URLを返します
}

// URLからQRコード作成 
//スプレッドシートからデータを取得
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var rows = sheet.getLastRow()-1; //1行目はカラム行のため-1
  var datas = sheet.getRange(2,2,rows,4).getValues();
 
//スプレッドシートの各行に対して繰り返し
  datas.forEach(function(data){
 
//各項目を抜き出し(先頭列は0)
  var url = data[3];
  var name = data[1];
   
//QR code APIを使用して上で取得したURLのQRコードを生成
  var qr_url = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=" + url;
   
//fetchする際のoptionを宣言
  var option = {
    method:"get"
  }
   
//fetch
  var response = UrlFetchApp.fetch(qr_url,option);
    
//fetchのレスポンスデータをblobとして取得
  var blob = response.getBlob();

//指定フォルダにQRコードの画像を格納
  var file = QRFolder.createFile(blob);
    
//ファイル名を変更
  file.setName(name + ".png");
   
});



### 自分で試したこと

0

5Answer

コード全体ではないようなのでコピペミスかもですが、53行目の}に対応する{がありませんね。インデントもところどころおかしいようです。まずはそのあたりの点検からですかね。もしコピペミスなら矛盾の無い範囲で切り取って提示してください。

2Like

Comments

  1. 53行目の}に対応する'{'がありませんね。

    42行目のforでは?

  2. ああ、そうですね。インデントに惑わされて間違えました。
    ちょっと見直しますね。

  3. @mohiro0714

    Questioner

    申し訳ありません。 
    整理し直してみます。皆さんに見ていただくのにふさわしくない書き方でした。
    勉強し直します!

私自身、あまり細かくコードをよく読み取れていませんが、短縮URLで1000待つ、というところがなんとなく怪しいかなー?と思っています。
また、現在は、まとめて短縮URLを取得し、まとめてQRコード取得となっていると思いますが、
1行ずつ(1URLずつ)、まず短縮URLを取得し、その次にQRコードを作成する、という形にしておいた方が、失敗が少ないのではないでしょうか

Windowsのcopilotに問い合わせ内容とコードを投げてみたところ、次のような回答がありましたので、参考までに転記します。(但しコードの内容は精査してないです)

コードの問題点は、短縮URLの生成部分が非同期に行われているため、QRコード生成時に短縮URLがまだ作成されていない可能性があります。これを解決するためには、短縮URLの生成が完了した後にQRコードを作成する必要があります。

以下は、コードを修正した例です。

// 初期設定
// 元画像が入っているフォルダIDを入力
var oldFolderID = 'ここに入力';
var oldFolder = DriveApp.getFolderById(oldFolderID);
// 作成されたQRコードを出力するフォルダIDを入力
var QRFolderID = 'ここに入力';
var QRFolder = DriveApp.getFolderById(QRFolderID);
// X.gdのAPIから短縮URLを作成するためのAPIキーを入力
var apiKey = 'ここに入力';
// 初期設定ここまで

function makeQR_shortenURL() {
  // 元画像フォルダ内のファイル名とURLを取得して、スプシに出力させる
  // スプレッドシートとシートの指定
  var activeSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = activeSpreadSheet.getSheetByName('QRコード作成用'); // 必要に応じて変更します
  // シートをクリア
  sheet.clear();
  // シートのタイトル行を設定
  sheet.appendRow(['', 'ファイル名', '拡張子なし', 'GoogleドライブでのURL', '短縮URL']);

  // フォルダ内のファイルを取得
  var files = oldFolder.getFiles();

  // ファイル名、拡張子なし、Googleドライブ上のURL、短縮URLを変数に代入
  while (files.hasNext()) {
    var file = files.next();
    var fileName = file.getName();
    var kakuNashi = fileName.substring(0, fileName.length - 4);
    var fileUrl = file.getUrl();
    var shortURL = shortenUrlWithXgd(fileUrl, apiKey);
    // ファイル名、拡張子なし、Googleドライブ上のURL、短縮URLをスプシに出力
    sheet.appendRow([, fileName, kakuNashi, fileUrl, shortURL]);
  }

  // QRコード生成を呼び出し
  generateQRCode();
}

// Googleドライブ上のURLから短縮URLを作成
function shortenUrlWithXgd(longUrl, apiKey) {
  var url = "https://xgd.io/V1/shorten?url=" + encodeURIComponent(longUrl) + "&key=" + apiKey;
  var options = {
    method: "GET",
    muteHttpExceptions: true
  };
  var response = UrlFetchApp.fetch(url, options);
  // 短縮化するURLが多いとサーバーの処理が間に合わないため1000ms待ってから
  Utilities.sleep(1000);
  // 正常に処理が行われなかった場合
  if (response.getResponseCode() !== 200) {
    Logger.log("Error: " + response.getContentText());
    throw new Error("Failed to shorten URL. Status code: " + response.getResponseCode());
  }

  var data = JSON.parse(response.getContentText());
  Logger.log("Shortened URL: " + data.shorturl); // 短縮URLをログに出力
  return data.shorturl; // 短縮URLを返します
}

// URLからQRコード作成
function generateQRCode() {
  var activeSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = activeSpreadSheet.getSheetByName('QRコード作成用'); // 必要に応じて変更します
  var rows = sheet.getLastRow() - 1; // 1行目はカラム行のため-1
  var datas = sheet.getRange(2, 2, rows, 4).getValues();

  // スプレッドシートの各行に対して繰り返し
  datas.forEach(function (data) {
    // 各項目を抜き出し(先頭列は0)
    var url = data[3];
    var name = data[1];

    // QR code APIを使用して上で取得したURLのQRコードを生成
    var qr_url = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=" + url;

    // fetchする際のoptionを宣言
    var option = {
      method: "get"
    };

    // fetch
    var response = UrlFetchApp.fetch(qr_url, option);

    // fetchのレスポンスデータをblobとして取得
    var blob = response.getBlob();

    // 指定フォルダにQRコードの画像を格納
    var file = QRFolder.createFile(blob);

    // ファイル名を変更
    file.setName(name + ".png");
  });
}

2Like

モジュールやクラスが分散しているのを説明用にピックアップされても読めないし
インデントはメチャクチャだし
問題が発生しているところだけのコードを書かないと誰もわかりません

1.スプレッド内からURLを取得
2.URLから短縮URLを取得
3.短縮URLからQRコード作成

全部書かれて動かないと言われても、どの段階で動かないのか?

2だったらサンプルのURLを引数にしたコードを
3だったらサンプルのURLを引数にしたコードを

1Like

インデント整形してみました。そして敢えて関数定義には深いインデントを付けました。

処理は

  1. URLを取得してシートに書く
  2. シートからURLを読んで短縮URLに変換してシートに書く
  3. シートから短縮URLを読んでQRコードを取得する

という流れなのですね。で、URLを取得してシートに書く手続きは関数 makeQR_shortenURL 内で行うようになっているようなのですが、この関数の呼び出しは行われていません。関数を定義しているだけで、呼んでいない。だからこのコードを実行してもシートは空のままだなのだと思います。

// 初期設定
// 元画像が入っているフォルダIDを入力
var oldFolderID = 'ここに入力';
var oldFolder = DriveApp.getFolderById(oldFolderID);
// 作成されたQRコードを出力するフォルダIDを入力
var QRFolderID = 'ここに入力';
var QRFolder = DriveApp.getFolderById(QRFolderID);
// X.gdのAPIから短縮URLを作成するためのAPIキーを入力
var apiKey = 'ここに入力';
// 初期設定ここまで

        function makeQR_shortenURL() {
          // 元画像フォルダ内のファイル名とURLを取得して、スプシに出力させる
          // スプレッドシートとシートの指定
          var activeSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
          var sheet = activeSpreadSheet.getSheetByName('QRコード作成用'); // 必要に応じて変更します
          // シートをクリア
          sheet.clear();
          // シートのタイトル行を設定
          sheet.appendRow(['', 'ファイル名', '拡張子なし', 'GoogleドライブでのURL', '短縮URL']);

          // フォルダ内のファイルを取得
          var files = oldFolder.getFiles();

          // ファイル名、拡張子なし、Googleドライブ上のURL、短縮URLを変数に代入
          while (files.hasNext()) {
            var file = files.next();
            var fileName = file.getName();
            var kakuNashi = fileName.substring(0, fileName.length -4);
            var fileUrl = file.getUrl();
            var shortURL = shortenUrlWithXgd(fileUrl, apiKey);
            // ファイル名、拡張子なし、Googleドライブ上のURL、短縮URLをスプシに出力
            sheet.appendRow([, fileName, kakuNashi, fileUrl, shortURL]);
          }
        }

// Googleドライブ上のURLから短縮URLを作成
// スプシから元のURLを取得して短縮URLを出力
var activeSpreadSheet = SpreadsheetApp.getActiveSpreadsheet();
var sheet = activeSpreadSheet.getSheetByName('QRコード作成用'); // 必要に応じて変更します
var lastRow = sheet.getLastRow();
for (var i = 2; i <= lastRow; i++) {
  // 元のURLがD列に入っている場合
  var longUrl = sheet.getRange(i, 4).getValue();
  // E列に既に短縮URLがあるか確認
  var existingShortUrl = sheet.getRange(i, 5).getValue();
  // E列が空で、D列にURLがある場合のみ短縮URLを生成
  if (longUrl && !existingShortUrl) {
    var shortUrl = shortenUrlWithXgd(longUrl, apiKey);
    // E列に短縮URLを表示
    sheet.getRange(i, 5).setValue(shortUrl); 
  }
}

        function shortenUrlWithXgd(longUrl, apiKey) {
          // X.gdのAPIを使用するためのurl設定
          var url = "https://xgd.io/V1/shorten?url=" + encodeURIComponent(longUrl) + "&key=" + apiKey; 
          var options = {
            method: "GET",
            muteHttpExceptions: true
          };

          var response = UrlFetchApp.fetch(url, options);
          //短縮化するURLが多いとサーバーの処理が間に合わないため1000ms待ってから
          Utilities.sleep(1000);
          // 正常に処理が行われなかった場合
          if (response.getResponseCode() !== 200) {
            Logger.log("Error: " + response.getContentText());
            throw new Error("Failed to shorten URL. Status code: " + response.getResponseCode());
          }

          var data = JSON.parse(response.getContentText());
          Logger.log("Shortened URL: " + data.shorturl); // 短縮URLをログに出力
          return data.shorturl; // 短縮URLを返します
        }

// URLからQRコード作成 
//スプレッドシートからデータを取得
var ss = SpreadsheetApp.getActiveSpreadsheet();
var rows = sheet.getLastRow()-1; //1行目はカラム行のため-1
var datas = sheet.getRange(2,2,rows,4).getValues();

//スプレッドシートの各行に対して繰り返し
datas.forEach(function(data){

  //各項目を抜き出し(先頭列は0)
  var url = data[3];
  var name = data[1];
  
  //QR code APIを使用して上で取得したURLのQRコードを生成
  var qr_url = "https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=" + url;
  
  //fetchする際のoptionを宣言
  var option = {
    method:"get"
  }
  
  //fetch
  var response = UrlFetchApp.fetch(qr_url,option);
    
  //fetchのレスポンスデータをblobとして取得
  var blob = response.getBlob();

  //指定フォルダにQRコードの画像を格納
  var file = QRFolder.createFile(blob);
    
  //ファイル名を変更
  file.setName(name + ".png");
 
});

あと、関数makeQR_shortenURL定義の後で、列Eが空なら列DのURLから短縮URLを得る処理があると思いますが、これが必要な理由はちょっとわかりませんでした。なぜなら関数makeQR_shortenURLが元のURLとともにそれの短縮URLも生成してシートに書きこんでいると思うので。

1Like

ありがとうございます。
まず、自分の書いたものを皆さんに見ていただくということについて軽く考えていました。
後から自分が見てもだれが見てもわかりやすい構造的な書き方を心掛けるべきでした。
@vramさんが書いてくださったように、こちらの意図している処理の流れを整理してお伝えすべきでした。
また、@itagagakiさんが 整理してくださった構造が大変見やすく参考になりました。
@calcMCalcmさん、新しい解決方法の提案、ありがとうございました。

いただいた回答案、ご指摘をもう一度見直し理解を深めたいと思います。
ありがとうございました!

0Like

Your answer might help someone💌