実現したいこと
Googleサーチコンソールから、2日前のサイト全体の以下のデータを取得し、スプレッドシートに出力したい。
- 表示回数
- クリック数
発生している問題・分からないこと
54行目のthrow new Errorにてエラーが発生しました。
43行目の「response = UrlFetchApp.fetch(apiURL, options);」にて取得したresponseの中身に問題があるようです。
エラーメッセージによると、このサイトの権限を持っていないと書かれています。しかし、実際には、GASを実行しているGoogleアカウントがサーチコンソールのオーナーです。サーチコンソールの「ユーザーと権限」というページを見て確認しました。
エラーメッセージ
error
1Error: API request failed with status 403: { 2 "error": { 3 "code": 403, 4 "message": "User does not have sufficient permission for site 'https://hoge-hoge.com/'. See also: https://support.google.com/webmasters/answer/2451999.", 5 "errors": [ 6 { 7 "message": "User does not have sufficient permission for site 'https://hoge-hoge.com/'. See also: https://support.google.com/webmasters/answer/2451999.", 8 "domain": "global", 9 "reason": "forbidden" 10 } 11 ] 12 } 13}
該当のソースコード
1function getSearchConsoleApi(){ 2 3 //GASスクリプトに紐づくスプレッドシートのアクティブなシート読み込み 4 const mySheet = SpreadsheetApp.getActiveSheet(); 5 6 //サーチコンソールの取得する開始日・終了日を定義※取得したい期間を設定 7 const startDate = "2024-10-01"; 8 const endDate = "2024-10-10"; 9 10 // サーチコンソールから取得するドメイン名を定義※書き換え必須 11 const siteDomain = "https://hoge-hoge.com/"; 12 13 // ドメインを正しくエンコードする 14 const encodedDomain = encodeURIComponent(siteDomain); 15 16 // リクエストするAPIのURLを設定する 17 const apiURL = `https://www.googleapis.com/webmasters/v3/sites/${encodedDomain}/searchAnalytics/query`; 18 19 20 //サーチコンソールから取得する最大クエリ数を設定する 21 const maxQuery = 1000; 22 23 //APIリクエスト時にセットするペイロード値を設定する 24 const payload = { 25 'startDate': startDate, 26 'endDate': endDate, 27 "dimensions": ["page", "query"], // ディメンションの設定方法はまだわかっていない。 28 "rowLimit": maxQuery 29 }; 30 31 const options = { 32 'payload': JSON.stringify(payload), 33 'method': 'POST', 34 'muteHttpExceptions': true, 35 'headers': { "Authorization": "Bearer " + checkAndRefreshToken() }, 36 'contentType': 'application/json' 37 }; 38 39 //APIリクエストを行った結果のJSONデータを変換する 40 let response; 41 42 try { 43 response = UrlFetchApp.fetch(apiURL, options); 44 const responseCode = response.getResponseCode(); 45 const responseBody = response.getContentText(); 46 console.log(`Response Code: ${responseCode}`); 47 console.log(`Response Body: ${responseBody}`); 48 49 // レスポンスの内容を確認 50 let responseText = response.getContentText(); 51 Logger.log("API Response: " + responseText); // デバッグ用ログ 52 53 if (response.getResponseCode() !== 200) { 54 throw new Error(`API request failed with status ${responseCode}: ${responseBody}`); 55 } 56 57 // json = JSON.parse(responseText); 58 let json = JSON.parse(responseBody); 59 60 if (!json.rows || json.rows.length === 0) { 61 throw new Error("No data returned from the API"); 62 } 63 } catch (error) { 64 Logger.log("Error: " + error.message); 65 return; // エラーが発生した場合、ここで処理を終了 66 } 67 68 //JSONデータを処理してqueryを配列に保存する処理をforループで行う 69 let queryData = []; 70 for (i = 0; i < maxQuery; i++) { 71 //queryDataを2次元配列に拡張する 72 queryData[i] = []; 73 //json変数のデータをqueryDataの配列に格納する 74 queryData[i][0] = json["rows"][i]["keys"][1]; 75 queryData[i][1] = json["rows"][i]["keys"][0]; 76 queryData[i][2] = json["rows"][i]["clicks"]; 77 queryData[i][3] = json["rows"][i]["impressions"]; 78 queryData[i][4] = json["rows"][i]["position"]; 79 queryData[i][5] = json["rows"][i]["ctr"]; 80 } 81 82 //スプレッドシートにqueryデータを書き込み 83 mySheet.getRange(2, 1, queryData.length, queryData[0].length).setValues(queryData); 84 //スプレッドシートのデータの順番を表示回数で降順で並び替え 85 mySheet.getRange(2, 1, queryData.length, queryData[0].length).sort({ column: 4, ascending: false }); 86 //クリック率のCTRの数値フォーマットを%に設定 87 mySheet.getRange(2, 6, queryData.length).setNumberFormat('0.00%'); 88} 89 90 91function checkAndRefreshToken() { 92 let token = ScriptApp.getOAuthToken(); 93 94 // トークンの有効性をテストする簡単なAPIコール 95 const testUrl = "https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + token; 96 const response = UrlFetchApp.fetch(testUrl, {'muteHttpExceptions': true}); 97 98 if (response.getResponseCode() !== 200) { 99 // トークンが無効な場合、新しいトークンを取得 100 ScriptApp.invalidateAuth(); 101 token = ScriptApp.getOAuthToken(); 102 } 103 104 return token; 105}
1{ 2 "timeZone": "Asia/Tokyo", 3 "exceptionLogging": "STACKDRIVER", 4 "runtimeVersion": "V8", 5 "dependencies": { 6 "enabledAdvancedServices": [ 7 { 8 "userSymbol": "AnalyticsData", 9 "serviceId": "analyticsdata", 10 "version": "v1beta" 11 } 12 ], 13 "libraries": [ 14 { 15 "userSymbol": "OAuth2", 16 "version": "43", 17 "libraryId": "1B7FSrk5Zi6L1rSxxTDgDEUsPzlukDsi4KGuTMorsTQHhGBzBkMun4iDF" 18 } 19 ] 20 }, 21 "oauthScopes": [ 22 "https://www.googleapis.com/auth/spreadsheets", 23 "https://www.googleapis.com/auth/webmasters.readonly", 24 "https://www.googleapis.com/auth/script.external_request" 25 ] 26}
試したこと・調べたこと
- teratailやGoogle等で検索した
- ソースコードを自分なりに変更した
- 知人に聞いた
- その他
上記の詳細・結果
このコード自体は、このページを参考にしました。
https://auto-worker.com/blog/?p=3294
このページの以下の箇所でエラー(内容は失念しました)が出たので、ChatGPTやClaudeに質問しつつコードを改善していきました。
json = JSON.parse(response);
補足
- GPCのGoogle Search Console APIは設定済み
- ライブラリから「OAuth2」を追加済み
- Apps Scriptエディターのプロジェクトの設定画面で、GCPのプロジェクト番号を設定済み
- Apps Scriptエディターのプロジェクトの設定画面で、以下の箇所にチェックマークを入れました。その結果、appsscript.jsonというスクリプトファイルが生成されました。そのスクリプトファイルには「oauthScopes」情報を追記しました。
「appsscript.json」マニフェスト ファイルをエディタで表示する
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。