๋ฐœํ–‰์ผ:

์ˆ˜์ •์ผ:

๊ตฌ๊ธ€ ์•ฑ์Šค ์Šคํฌ๋ฆฝํŠธ๋กœ ์ฟ ํŒก ์ƒํ’ˆ ์ž๋™ ํ‘œ์‹œํ•˜๊ธฐ๏ฝœ์ฝ”๋“œ์™€ ์„ค์ • ๋ฐฉ๋ฒ•

์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ์ƒํ’ˆ์„ ๋ธ”๋กœ๊ทธ์— ์ž๋™ ๋…ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. API ํ‚ค ์„ค์ •, Apps Script ํ™œ์šฉ, ์‹ค์‹œ๊ฐ„ ์ƒํ’ˆ ์—…๋ฐ์ดํŠธ ์ž๋™ํ™”๊นŒ์ง€ ์ž์„ธํžˆ ์•ˆ๋‚ดํ•ฉ๋‹ˆ๋‹ค.

๋ธ”๋กœ๊ทธ๋ฅผ ์šด์˜ํ•˜๋ฉด์„œ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ์ˆ˜์ต์„ ์˜ฌ๋ฆฌ๊ธฐ ์œ„ํ•ด ๋งค๋ฒˆ ์ƒํ’ˆ ๋งํฌ๋ฅผ ์ผ์ผ์ด ๊ฒ€์ƒ‰ํ•˜๊ณ  ์‚ฝ์ž…ํ•˜๋Š” ์ผ์ด ๋ฒˆ๊ฑฐ๋กญ๊ณ  ์‹œ๊ฐ„ ๋‚ญ๋น„์ฒ˜๋Ÿผ ๋А๊ปด์ง€์…จ๋‹ค๋ฉด, ์ด ๊ธ€์ด ๋ฐ”๋กœ ํ•ด๋‹ต์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์ฝ˜ํ…์ธ ๊ฐ€ ๋งŽ์•„์งˆ์ˆ˜๋ก ์ˆ˜๋™ ์ž‘์—…์˜ ํ•œ๊ณ„๋Š” ๋ถ„๋ช…ํ•ด์ง€๊ธฐ ๋งˆ๋ จ์ด์ฃ .

์˜ค๋Š˜์€ Google Apps Script๋ฅผ ํ™œ์šฉํ•ด ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ์ƒํ’ˆ์„ ์ž๋™์œผ๋กœ ๋ถˆ๋Ÿฌ์™€ ๋ธ”๋กœ๊ทธ์— ๋…ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ํ•œ ๋ฒˆ๋งŒ ์„ค์ •ํ•˜๋ฉด ์ตœ์‹  ์ฟ ํŒก ์ƒํ’ˆ ์ •๋ณด๊ฐ€ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜๋ฉฐ ์ž๋™ ๋ฐ˜์˜๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋งค๋ฒˆ ์ƒˆ๋กœ ์‚ฝ์ž…ํ•  ํ•„์š” ์—†์ด ๊พธ์ค€ํ•œ ์ˆ˜์ต ์ฐฝ์ถœ๊ณผ ๊ด€๋ฆฌ ํšจ์œจ์„ฑ์„ ๋™์‹œ์— ์žก์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ธ”๋กœ๊ทธ ์ˆ˜์ต ์ž๋™ํ™”, ์ฟ ํŒก API ๊ธฐ๋ฐ˜ ์‹ค์‹œ๊ฐ„ ์ƒํ’ˆ ์—…๋ฐ์ดํŠธ, ๊ทธ๋ฆฌ๊ณ  ๋ฐ˜์‘ํ˜• ๋””์ž์ธ ์ ์šฉ๊นŒ์ง€, ์ง€๊ธˆ๋ถ€ํ„ฐ ์†Œ๊ฐœํ•  ๋ฐฉ๋ฒ•์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค๋ฅผ ํ™œ์šฉํ•œ ๋ธ”๋กœ๊ทธ ์šด์˜์— ์žˆ์–ด ๊ผญ ํ•„์š”ํ•œ ์ „๋žต์ด ๋  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ฟ ํŒก ํŒŒํŠธ๋„ˆ ์ž๋™ ๊ด‘๊ณ  ์ ์šฉ๋ฐฉ๋ฒ•

๋จผ์ € ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ์‚ฌ์ดํŠธ์— ์ ‘์†ํ•ด Access Key์™€ Secret Key๋ฅผ ๋ณต์‚ฌํ•ด ๋ฉ”๋ชจํ•ด ๋‘์„ธ์š”.

1. ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ์‚ฌ์ดํŠธ ์ ‘์† ํ›„ API ํ‚ค ๋ณต์‚ฌ

์ฟ ํŒก ํŒŒํŠธ๋„ˆ ์ƒํ’ˆ ์ž๋™ ๋“ฑ๋ก์„ ์œ„ํ•ด apiํ‚ค ๋ณต์‚ฌ

2. Google Apps Script, ํŒŒํŠธ๋„ˆ์Šค ์ž๋™ํ™”

Google Apps Script๋Š” ๊ตฌ๊ธ€์ด ์ œ๊ณตํ•˜๋Š” ํด๋ผ์šฐ๋“œ ๊ธฐ๋ฐ˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค. ๊ตฌ๊ธ€ ์Šคํ”„๋ ˆ๋“œ์‹œํŠธ, ์ง€๋ฉ”์ผ ๋“ฑ๊ณผ ์‰ฝ๊ฒŒ ์—ฐ๋™๋˜๋ฉฐ ์™ธ๋ถ€ API์™€์˜ ํ†ต์‹ ๋„ ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

์™œ Apps Script์ธ๊ฐ€์š”?

  • ๋ฌด๋ฃŒ ๋ฐ ์„œ๋ฒ„๋ฆฌ์Šค: ๋ณ„๋„ ์„œ๋ฒ„ ์—†์ด ๊ตฌ๊ธ€ ์ธํ”„๋ผ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ์‰ฌ์šด ์—ฐ๋™: ๊ตฌ๊ธ€ ์„œ๋น„์Šค ๋ฐ ์™ธ๋ถ€ API์™€ ๊ฐ„๋‹จํ•œ ์—ฐ๊ฒฐ
  • ์ž๋™ํ™”: 24์‹œ๊ฐ„ ์ž๋™์œผ๋กœ ์ตœ์‹  ์ƒํ’ˆ ์ •๋ณด ๊ฐ€์ ธ์˜ค๊ธฐ

์ด Apps Script๋กœ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค API์™€ ํ†ต์‹ ํ•˜์—ฌ ์ƒํ’ˆ๋ช…, ๊ฐ€๊ฒฉ, ์ด๋ฏธ์ง€, ๋งํฌ ๋“ฑ์„ JSON ํ˜•ํƒœ๋กœ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

3. Google Apps Script ์„ค์ • ๋ฐ ์‚ฌ์šฉ ๋ฐฉ๋ฒ•

1. Google Apps Script ์ ‘์†ํ•ฉ๋‹ˆ๋‹ค.

๋ธ”๋กœ๊ทธ ์ฟ ํŒก ์ž๋™ ๊ด‘๊ณ  ์„ค์ •๋ฐฉ๋ฒ•2

2. ๋จผ์ € ์ฟ ํŒก API์™€ ์—ฐ๋™ํ•  Apps Script ์ƒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•œ ํ›„ ๊ธฐ๋ณธ์ ์œผ๋กœ ์„ค์ •๋œ ์ฝ”๋“œ ์‚ญ์ œํ•ฉ๋‹ˆ๋‹ค.

Google Apps Script ์ฟ ํŒก API ์„ค์ •๋ฐฉ๋ฒ•3

3. Code.gs ํŒŒ์ผ์— ์ฝ”๋“œ ๋ถ™์—ฌ๋„ฃ๊ธฐ

  • ์ „์ฒด Apps Script ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•ด ๋ถ™์—ฌ๋„ฃ๊ธฐ
  • COUPANG_ACCESS_KEY, COUPANG_SECRET_KEY, COUPANG_AFFILIATE_ID๋ฅผ ์ž์‹ ์˜ ์ •๋ณด๋กœ ์ˆ˜์ •
  • ์ฟ ํŒก ์ƒํ’ˆ์ค‘ ๋…ธ์ถœํ•˜๊ณ ์ž ํ•˜๋Š” ์นดํ…Œ๊ณ ๋ฆฌ ๋ณ€๊ฒฝ.
  • ๋‚˜๋จธ์ง€ ๊ทธ๋Œ€๋กœ....

์ฟ ํŒก ์นดํ…Œ๊ณ ๋ฆฌ ์ƒํ’ˆ ๋ฒˆํ˜ธ

Id ์ด๋ฆ„
1001 ์—ฌ์„ฑํŒจ์…˜
1002 ๋‚จ์„ฑํŒจ์…˜
1010 ๋ทฐํ‹ฐ
1011 ์ถœ์‚ฐ/์œ ์•„๋™
1012 ์‹ํ’ˆ
1013 ์ฃผ๋ฐฉ์šฉํ’ˆ
1014 ์ƒํ™œ์šฉํ’ˆ
1015 ํ™ˆ์ธํ…Œ๋ฆฌ์–ด
1016 ๊ฐ€์ „๋””์ง€ํ„ธ
1017 ์Šคํฌ์ธ /๋ ˆ์ €
1018 ์ž๋™์ฐจ์šฉํ’ˆ
1019 ๋„์„œ/์Œ๋ฐ˜/DVD
1020 ์™„๊ตฌ/์ทจ๋ฏธ
1021 ๋ฌธ๊ตฌ/์˜คํ”ผ์Šค
1024 ํ—ฌ์Šค/๊ฑด๊ฐ•์‹ํ’ˆ
1025 ๊ตญ๋‚ด์—ฌํ–‰
1026 ํ•ด์™ธ์—ฌํ–‰
1029 ๋ฐ˜๋ ค๋™๋ฌผ์šฉํ’ˆ
1030 ์œ ์•„๋™ํŒจ์…˜

์ฟ ํŒก ์นดํ…Œ๊ณ ๋ฆฌ ์ƒํ’ˆ

const PRODUCT_LIST_API_PATH ="/v2/providers/affiliate_open_api/apis/openapi/products/bestcategories/1001?limit=50"

์ฟ ํŒก PL ์ƒํ’ˆ

const PRODUCT_LIST_API_PATH = "/v2/providers/affiliate_open_api/apis/openapi/products/coupangPL";
// ==== ์„ค์ •๊ฐ’ (๋ณธ์ธ์˜ ์ •๋ณด๋กœ ๋ณ€๊ฒฝ) ====
const COUPANG_ACCESS_KEY = "๋‹น์‹ ์˜ ACCESS KEY"; // ์ฟ ํŒก API Access Key
const COUPANG_SECRET_KEY = "๋‹น์‹ ์˜ SECRET KEY"; // ์ฟ ํŒก API Secret Key
const COUPANG_AFFILIATE_ID = "๋‹น์‹ ์˜ AFFILIATE ID"; // ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ID (lptag=AF1234567์˜ AF1234567 ๋ถ€๋ถ„)

// ์ฟ ํŒก API ๊ธฐ๋ณธ URL ๋ฐ Deep Link ๊ฒฝ๋กœ
const COUPANG_API_BASE_URL = "https://api-gateway.coupang.com";
const DEEPLINK_API_PATH = "/v2/providers/affiliate_open_api/apis/openapi/v1/deeplink";

// ์ƒํ’ˆ ๋ชฉ๋ก ์กฐํšŒ API ๊ฒฝ๋กœ(์ƒํ’ˆ ์นดํ…Œ๊ณ ๋ฆฌ๋กœ ๋ณ€๊ฒฝ)
const PRODUCT_LIST_API_PATH = "/v2/providers/affiliate_open_api/apis/openapi/products/coupangPL";

// ---

// ==== GMT ๋‚ ์งœ ํ˜•์‹ ์ƒ์„ฑ ํ•จ์ˆ˜ (yyMMdd'T'HHmmss'Z' ํฌ๋งท) ====
function getCoupangApiDate() {
 const date = new Date();
 const year = date.getUTCFullYear().toString().substring(2); // YY (์˜ˆ: 2025 - 25)
 const month = (date.getUTCMonth() + 1).toString().padStart(2, '0'); // MM
 const day = date.getUTCDate().toString().padStart(2, '0'); // DD
 const hours = date.getUTCHours().toString().padStart(2, '0'); // HH
 const minutes = date.getUTCMinutes().toString().padStart(2, '0'); // mm
 const seconds = date.getUTCSeconds().toString().padStart(2, '0'); // ss

 return `${year}${month}${day}T${hours}${minutes}${seconds}Z`;
}

// ==== HMAC Signature ์ƒ์„ฑ ํ•จ์ˆ˜ ====
function generateCoupangSignature(method, uri, secretKey, accessKey) {
 const parts = uri.split('?');
 const path = parts[0];
 const query = (parts.length === 2) ? parts[1] : '';

 const datetime = getCoupangApiDate();
 const stringToSign = `${datetime}${method}${path}${query}`;

 const signatureBytes = Utilities.computeHmacSha256Signature(stringToSign, secretKey);

 const signatureHex = bytesToHex(signatureBytes);

 return `CEA algorithm=HmacSHA256, access-key=${accessKey}, signed-date=${datetime}, signature=${signatureHex}`;
}

// ==== ๋ฐ”์ดํŠธ ๋ฐฐ์—ด์„ 16์ง„์ˆ˜ ๋ฌธ์ž์—ด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ํ—ฌํผ ํ•จ์ˆ˜ ====
function bytesToHex(bytes) {
 return Array.from(bytes, function(byte) {
 return ('0' + (byte & 0xFF).toString(16)).slice(-2);
 }).join('');
}

// ---

// ==== Deep Link ์ƒ์„ฑ API ํ˜ธ์ถœ ํ•จ์ˆ˜ (์‚ฌ์šฉ์ž ์š”์ฒญ ์‹œ POST๋กœ ํ˜ธ์ถœ ๊ฐ€๋Šฅ) ====
function generateCoupangDeepLink(coupangUrls) {
 const method = 'POST';
 const uri = DEEPLINK_API_PATH;
 const url = COUPANG_API_BASE_URL + uri;

 const requestPayload = {
 coupangUrls: coupangUrls
 };
 const requestBody = JSON.stringify(requestPayload);

 const authorizationHeader = generateCoupangSignature(method, uri, COUPANG_SECRET_KEY, COUPANG_ACCESS_KEY);

 const options = {
 method: method,
 headers: {
 'Authorization': authorizationHeader,
 'Content-Type': 'application/json;charset=UTF-8'
 },
 payload: requestBody,
 muteHttpExceptions: true
 };

 try {
 const response = UrlFetchApp.fetch(url, options);
 const responseCode = response.getResponseCode();
 const responseBody = response.getContentText();

 if (responseCode === 200) {
 const parsedResponse = JSON.parse(responseBody);
 Logger.log("Deep Link API Response: " + JSON.stringify(parsedResponse, null, 2));
 return parsedResponse;
 } else {
 Logger.log(`API Error: ${responseCode} - ${responseBody}`);
 return null;
 }
 } catch (e) {
 Logger.log(`Fetch Error: ${e.message}`);
 return null;
 }
}

// ---

// ==== ์ƒํ’ˆ ๋ชฉ๋ก ์กฐํšŒ API ํ˜ธ์ถœ ํ•จ์ˆ˜ ====
function fetchCoupangProducts(limit = 20) { // ๊ธฐ๋ณธ๊ฐ’ 20๊ฐœ
 const method = 'GET';
 const uri = `${PRODUCT_LIST_API_PATH}?limit=${limit}`;
 const url = COUPANG_API_BASE_URL + uri;

 const authorizationHeader = generateCoupangSignature(method, uri, COUPANG_SECRET_KEY, COUPANG_ACCESS_KEY);

 const options = {
 method: method,
 headers: {
 'Authorization': authorizationHeader,
 },
 muteHttpExceptions: true
 };

 try {
 const response = UrlFetchApp.fetch(url, options);
 const responseCode = response.getResponseCode();
 const responseBody = response.getContentText();

 if (responseCode === 200) {
 const parsedResponse = JSON.parse(responseBody);
 Logger.log(`Product List API Response (limit=${limit}): ` + JSON.stringify(parsedResponse, null, 2));
 return parsedResponse;
 } else {
 Logger.log(`API Error: ${responseCode} - ${responseBody}`);
 return null;
 }
 } catch (e) {
 Logger.log(`Fetch Error: ${e.message}`);
 return null;
 }
}

// ---

// ==== ์›น ์•ฑ์œผ๋กœ ๋ฐฐํฌํ•  ํ•จ์ˆ˜ (GET ์š”์ฒญ ์ฒ˜๋ฆฌ: ์ƒํ’ˆ ๋ชฉ๋ก ์กฐํšŒ) ====
function doGet(e) {
 let limit = parseInt(e.parameter.limit); // ๋ธ”๋กœ๊ทธ์—์„œ ๋ณด๋‚ธ limit ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋ฐ›์Œ
 if (isNaN(limit) || limit 1 || limit 100) {
 limit = 20; // limit ๊ฐ’์ด ์—†๊ฑฐ๋‚˜ ์œ ํšจํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ 20๊ฐœ
 }

 const productsResult = fetchCoupangProducts(limit);

 // ์ฟ ํŒก API ์‘๋‹ต์—์„œ 'rCode'๊ฐ€ '0'์ด๊ณ  'data' ํ•„๋“œ๊ฐ€ ์กด์žฌํ•  ๋•Œ๋งŒ 'data' ํ•„๋“œ์˜ ๋‚ด์šฉ์„ ๋ฐ˜ํ™˜
 if (productsResult && productsResult.rCode === "0" && productsResult.data) {
 return ContentService.createTextOutput(JSON.stringify(productsResult.data, null, 2))
 .setMimeType(ContentService.MimeType.JSON);
 } else {
 // ์˜ค๋ฅ˜๊ฐ€ ์žˆ๊ฑฐ๋‚˜ ๋ฐ์ดํ„ฐ๊ฐ€ ์—†๋Š” ๊ฒฝ์šฐ, ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€๋ฅผ ํฌํ•จํ•˜์—ฌ ๋ฐ˜ํ™˜
 const errorMessage = productsResult && productsResult.rMessage ? productsResult.rMessage : "์ƒํ’ˆ ๋ชฉ๋ก ์กฐํšŒ ์‹คํŒจ ๋˜๋Š” ๋ฐ์ดํ„ฐ ์—†์Œ.";
 Logger.log(`์ƒํ’ˆ ์กฐํšŒ ์‹คํŒจ: ${errorMessage}`);
 return ContentService.createTextOutput(JSON.stringify({ error: errorMessage }))
 .setMimeType(ContentService.MimeType.JSON);
 }
}

// ==== ์›น ์•ฑ์œผ๋กœ ๋ฐฐํฌํ•  ํ•จ์ˆ˜ (POST ์š”์ฒญ ์ฒ˜๋ฆฌ: Deep Link ์ƒ์„ฑ - ํ˜„์žฌ ๋ธ”๋กœ๊ทธ์—์„œ๋Š” GET๋งŒ ์‚ฌ์šฉ) ====
function doPost(e) {
 try {
 const requestData = JSON.parse(e.postData.contents);
 const coupangUrls = requestData.coupangUrls;

 if (!coupangUrls || !Array.isArray(coupangUrls) || coupangUrls.length === 0) {
 return ContentService.createTextOutput(JSON.stringify({ error: "'coupangUrls' ๋ฐฐ์—ด์„ JSON ๋ฐ”๋””์— ํฌํ•จํ•ด์ฃผ์„ธ์š”." }))
 .setMimeType(ContentService.MimeType.JSON);
 }

 const deepLinkResult = generateCoupangDeepLink(coupangUrls);

 if (deepLinkResult) {
 return ContentService.createTextOutput(JSON.stringify(deepLinkResult, null, 2))
 .setMimeType(ContentService.MimeType.JSON);
 } else {
 return ContentService.createTextOutput(JSON.stringify({ error: "Deep Link ์ƒ์„ฑ ์‹คํŒจ" }))
 .setMimeType(ContentService.MimeType.JSON);
 }

 } catch (err) {
 Logger.log("doPost ์˜ค๋ฅ˜: " + err.message);
 return ContentService.createTextOutput(JSON.stringify({ error: "์š”์ฒญ ์ฒ˜๋ฆฌ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: " + err.message }))
 .setMimeType(ContentService.MimeType.JSON);
 }
}

4. Apps Script ์›น ์•ฑ ๋ฐฐํฌ

์ฟ ํŒก ์ œํœด๋งˆ์ผ€ํŒ… ์ž๋™ํ™”
  • ์ฝ”๋“œ๋ฅผ ์ €์žฅํ•œ ํ›„, ์ƒ๋‹จ ๋ฉ”๋‰ด์—์„œ ๋ฐฐํฌ ์ƒˆ ๋ฐฐํฌ๋ฅผ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

5. ์œ ํ˜• ์„ ํƒ์—์„œ ์›น ์•ฑ์„ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.

๋ธ”๋กœ๊ทธ ์ž๋™ ์ƒํ’ˆ ์‚ฝ์ž…
ํ‹ฐ์Šคํ† ๋ฆฌ ์ฟ ํŒก ์ž๋™ ์ฝ”๋“œ

7.์ด๋ฏธ์ง€ ์ˆœ์„œ๋Œ€๋กœ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ฉ๋‹ˆ๋‹ค.

์ฟ ํŒก ์ƒํ’ˆ ์ž๋™์—…๋ฐ์ดํŠธ ๋ฐฉ๋ฒ•

8. ALLOW ๋ฒ„ํŠผ์„ ํด๋ฆญํ•˜๊ณ  ์ฃผ์†Œ ๋ณต์‚ฌํ›„ ์™„๋ฃŒ

์Šคํฌ๋ฆฝํŠธ๋กœ ์ฟ ํŒก ๊ด‘๊ณ  ๋„์šฐ๊ธฐ ๋ฐฉ๋ฒ•

9. ๋ณต์‚ฌํ•œ ์ฃผ์†Œ ์ ‘์† ๋ฐ์ดํ„ฐ ํ™•์ธํ›„ ์ฃผ์†Œ ๋ฉ”๋ชจ

๊ธด ์›น ์•ฑ ์ฃผ์†Œ(https://script.googleusercontent.com/macros/echo?...)๊ฐ€ ์ƒ์„ฑ๋ฉ๋‹ˆ๋‹ค. ์ด ์ฃผ์†Œ๋ฅผ ์ •ํ™•ํžˆ ๋ณต์‚ฌํ•ด ๋‘์„ธ์š”. ์ด URL์€ ๋ธ”๋กœ๊ทธ์—์„œ ์›น ์•ฑ์— ์ ‘๊ทผํ•˜๋Š” ์œ ์ผํ•œ ๊ฒฝ๋กœ์ž…๋‹ˆ๋‹ค.

์ฟ ํŒก ์ œํœด์ฝ”๋“œ ์ž๋™ ๋ฐ˜์˜

ํ‹ฐ์Šคํ† ๋ฆฌ ๋ธ”๋กœ๊ทธ์— ์ฟ ํŒก ์ƒํ’ˆ ๋…ธ์ถœ ์ฝ”๋“œ ์ ์šฉ

์ด์ œ ์ƒํ’ˆ์„ ๋…ธ์ถœํ•˜๊ธฐ ์œ„ํ•ด ๋ธ”๋กœ๊ทธ์— ์„ค์ •์„ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

1. ํ‹ฐ์Šคํ† ๋ฆฌ ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€ HTML ๋ชจ๋“œ

์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ์ฟ ํŒก ์ƒํ’ˆ์„ ์ž๋™์œผ๋กœ ๋…ธ์ถœํ•˜๊ณ ์ž ํ•˜๋Š” ์œ„์น˜์— ์‚ฝ์ž…ํ•ฉ๋‹ˆ๋‹ค.
์ƒˆ ๊ธ€์— ์ ์šฉํ•˜๊ฑฐ๋‚˜ ๊ธฐ์กด ๊ธ€์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ธฐ๋ณธ ์Šคํ‚จ์— ๊ณ ์ •ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.
์—๋””ํ„ฐ์—์„œ HTML ๋ชจ๋“œ๋กœ ์ „ํ™˜ํ•œ ๋’ค ์ฝ”๋“œ๋ฅผ ๋ถ™์—ฌ๋„ฃ์–ด ์ฃผ์„ธ์š”.

p์ด ํฌ์ŠคํŒ…์€ ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ํ™œ๋™์˜ ์ผํ™˜์œผ๋กœ ์ผ์ •์•ก์˜ ์ˆ˜์ˆ˜๋ฃŒ๋ฅผ ์ œ๊ณต๋ฐ›์Šต๋‹ˆ๋‹ค./p
div id="coupang-products-container"
 p์ž ์‹œ๋งŒ ๊ธฐ๋‹ค๋ ค์ฃผ์„ธ์š”. ์ƒํ’ˆ ์ •๋ณด๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.../p
/div

2. HTML/JavaScript ์ฝ”๋“œ ์‚ฝ์ž…

  • ์ œ๊ณต๋œ ์ฝ”๋“œ๋ฅผ ๋ณต์‚ฌํ•ด HTML ๋ชจ๋“œ์— ๋ถ™์—ฌ๋„ฃ์Šต๋‹ˆ๋‹ค.
  • ์ค‘์š”: ์ฝ”๋“œ ๋‚ด const apiUrl = 'URL ์ž…๋ ฅ&limit=3'; ์ž…๋ ฅ๋ถ€๋ถ„์— ๋ณต์‚ฌํ•œ ์›น ์•ฑ URL์„ ์ •ํ™•ํžˆ ์‚ฝ์ž…ํ•˜์„ธ์š”.

const apiUrl = '๋ณต์‚ฌ URL์ž…๋ ฅ_&limit=3'; // ๋…ธ์ถœ ์ƒํ’ˆ์ˆ˜ ์„ค์ • (ํ˜„์žฌ 3๊ฐœ)

script
async function loadCoupangProducts() {
 const container = document.getElementById('coupang-products-container');
 const apiUrl = 'URL ์ž…๋ ฅ&limit=3'; // ์‹ค์ œ URL ์ž…๋ ฅ

 try {
 const response = await fetch(apiUrl);
 if (!response.ok) throw new Error(`API ์š”์ฒญ ์‹คํŒจ: ${response.status}`);
 
 const data = await response.json();
 
 const products = Array.isArray(data) ? data.slice(0, 3) :
 data?.data?.slice(0, 3) || [];

 if (products.length 0) {
 let html = `
 p class="product-title"์ฟ ํŒก ์ถ”์ฒœ ์ƒํ’ˆ/p
 div class="product-grid"
 ${products.map(product = `
 div class="product-item"
 a href="${product.productUrl || '#'}" target="_blank" rel="noopener"
 img class="product-image" src="${product.productImage || 'https://via.placeholder.com/150'}" alt="${product.productName || ''}"
 p class="product-name"${product.productName || '์ƒํ’ˆ๋ช… ์—†์Œ'}/h3
 p class="product-price"${product.productPrice?.toLocaleString() + '์›' || '๊ฐ€๊ฒฉ ์ •๋ณด ์—†์Œ'}/p
 button class="detail-button"์ž์„ธํžˆ ๋ณด๊ธฐ/button
 /a
 /div
 `).join('')}
 /div
 `;
 container.innerHTML = html;
 } else {
 container.innerHTML = 'p class="no-products"ํ‘œ์‹œํ•  ์ƒํ’ˆ์ด ์—†์Šต๋‹ˆ๋‹ค./p';
 }
 } catch (error) {
 container.innerHTML = 'p class="error-message"์ƒํ’ˆ ๋กœ๋”ฉ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ/p';
 console.error(error);
 }
}

window.addEventListener('DOMContentLoaded', loadCoupangProducts);
/script

3. ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ์ž๋™ ๋…ธ์ถœ ์ƒํ’ˆ์— CSS ์ ์šฉ

์ƒํ’ˆ CSS๋Š” ๋ธ”๋กœ๊ทธ ์Šคํƒ€์ผ์— ๋งž๊ฒŒ ์ž์œ ๋กญ๊ฒŒ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์•„๋ž˜๋Š” ๋‹คํฌ ๋ชจ๋“œ์™€ ๋ชจ๋ฐ”์ผ์— ์ตœ์ ํ™”๋œ ๊ธฐ๋ณธ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

/* ์ƒํ’ˆ ์ปจํ…Œ์ด๋„ˆ */
#coupang-products-container{
max-width:1000px; 
}
.product-grid {
 display: grid;
 /* ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋ฐ”์ผ์—์„œ 1์—ด๋กœ ํ‘œ์‹œ */
 grid-template-columns: repeat(1, 1fr);
 gap: 20px;
 margin-top: 20px;
}

/* ๊ฐœ๋ณ„ ์ƒํ’ˆ ์Šคํƒ€์ผ */
.product-item {
 border: 1px solid #eee;
 padding: 15px;
 border-radius: 8px;
 text-align: center;
 transition: transform 0.2s;
}

.product-item:hover {
 transform: translateY(-5px);
 box-shadow: 0 5px 15px rgba(0,0,0,0.1);
}

.product-image {
 max-width: 100%;
 object-fit: contain;
 border-radius: 4px;
 margin-bottom: 10px;
}

.product-name {
 font-size: 1.1rem;
 margin: 0 0 10px;
 height: 3em;
 overflow: hidden;
 display: -webkit-box;
 -webkit-line-clamp: 2;
 -webkit-box-orient: vertical;
}

.product-price {
 font-size: 1.2rem;
 font-weight: bold;
 color: #FF0000;
 margin: 0;
}

.detail-button {
 background-color: var(--dark); /* ์ด ๋ณ€์ˆ˜๊ฐ€ ์ •์˜๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค๋ฉด ๋‹ค๋ฅธ ์ƒ‰์ƒ ์ฝ”๋“œ๋กœ ๋ณ€๊ฒฝํ•˜์„ธ์š” (์˜ˆ: #1a73e8) */
 color: white;
 padding: 8px 15px;
 border: none;
 border-radius: 5px;
 cursor: pointer;
 margin-top: 15px;
 width: 100%;
}

/* ๊ธฐํƒ€ ์Šคํƒ€์ผ */
.product-title {
 font-size: 1.6rem;
 color: #333;
 margin-bottom: 15px;
}

.no-products,
.error-message {
 color: #666;
 text-align: center;
 padding: 20px;
}

---

/* === ๋ฐ˜์‘ํ˜• ๋ฏธ๋””์–ด ์ฟผ๋ฆฌ ์ถ”๊ฐ€ === */

/* ํƒœ๋ธ”๋ฆฟ (ํ™”๋ฉด ๋„ˆ๋น„๊ฐ€ 600px ์ด์ƒ์ผ ๋•Œ) */
@media (min-width: 600px) {
 .product-grid {
 grid-template-columns: repeat(2, 1fr); /* 2์—ด๋กœ ๋ณ€๊ฒฝ */
 }
}

/* ๋ฐ์Šคํฌํ†ฑ (ํ™”๋ฉด ๋„ˆ๋น„๊ฐ€ 992px ์ด์ƒ์ผ ๋•Œ) */
@media (min-width: 992px) {
 .product-grid {
 grid-template-columns: repeat(3, 1fr); /* 3์—ด๋กœ ๋ณ€๊ฒฝ */
 }
}

๊ฒ€์ƒ‰ ์ตœ์ ํ™”(SEO) ๋ฐ ์ถ”๊ฐ€ ํŒ

  • HTML ๊ตฌ์กฐ: ์ƒํ’ˆ ๋ชฉ๋ก์„ ๊ฐ์‹ธ๋Š” div์™€ h2 ํƒœ๊ทธ๋Š” ๊ฒ€์ƒ‰ ์—”์ง„์ด ์ฝ˜ํ…์ธ ์˜ ์ค‘์š”๋„๋ฅผ ํŒŒ์•…ํ•˜๋Š” ๋ฐ ๋„์›€์„ ์ค๋‹ˆ๋‹ค. h2์ฟ ํŒก ์ถ”์ฒœ ์ƒํ’ˆ/h2์ฒ˜๋Ÿผ ํ‚ค์›Œ๋“œ๋ฅผ ํฌํ•จํ•˜์„ธ์š”.
  • ์ด๋ฏธ์ง€ alt ์†์„ฑ:alt="${productName}"์€ ์ด๋ฏธ์ง€ ์ ‘๊ทผ์„ฑ๊ณผ SEO ํ–ฅ์ƒ์— ํšจ๊ณผ์ ์ž…๋‹ˆ๋‹ค.
  • ๋ฐ˜์‘ํ˜• ๋””์ž์ธ:display: grid๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ชจ๋ฐ”์ผ์—์„œ๋„ ์ƒํ’ˆ์ด ๊น”๋”ํ•˜๊ฒŒ ๋ณด์ž…๋‹ˆ๋‹ค.
  • ์ƒํ’ˆ ๊ฐœ์ˆ˜ ์กฐ์ ˆ:const queryLimit = 5; ๊ฐ’์„ ๋ณ€๊ฒฝํ•ด ๋…ธ์ถœ ์ƒํ’ˆ ๊ฐœ์ˆ˜๋ฅผ ์ž์œ ๋กญ๊ฒŒ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ: queryLimit = 10;

์ด ๊ณผ์ •์„ ํ†ตํ•ด ๋ธ”๋กœ๊ทธ๋Š” ์ฟ ํŒก ํŒŒํŠธ๋„ˆ์Šค ์ˆ˜์ต์„ ์œ„ํ•œ ๊ฐ•๋ ฅํ•œ ์ž๋™ํ™” ๋„๊ตฌ๋ฅผ ๊ฐ–์ถ”๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ๋ฐฉ๋ฌธ์ž๋“ค์€ ํ•ญ์ƒ ์ตœ์‹  ์ƒํ’ˆ ์ •๋ณด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์–ด ํด๋ฆญ๋ฅ ๊ณผ ์ „ํ™˜์œจ ํ–ฅ์ƒ์— ๊ธฐ์—ฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์„ฑ๊ณต์ ์ธ ๋ธ”๋กœ๊ทธ ์šด์˜์„ ์‘์›ํ•ฉ๋‹ˆ๋‹ค!