3.1-5. [Apps Script+네이버 API] 활용한 쇼핑 크롤링 실습

네가 위에서 만들어준 아래 스크립트를 구글 colab이 아니라, Apps Script에서 구현이 가능해. Apps Script를 활용해서 index.html에서 키워드와 검색 개수를 입력받고, 스크립트 진행 후에, 결과를 구글 sheet로 받는 것을 의미하는 거야. --- - 네이버 쇼핑 검색 API로 원하는 개수(최대 1000개)만큼 수집하고, 중고·렌탈·해외직구/구매대행을 제외하며, 결과를 Pandas DataFrame → CSV(영문 파일명) 으로 저장하는 스크립트
💬
GPT
좋죠! Apps Script 웹앱으로 동작하도록 예시를 드릴게요.
index.html에서 키워드/수집 개수를 입력 → 서버(Code.gs)가 네이버 쇼핑 API를 페이지네이션으로 호출 → 중고/렌탈/해외직구·구매대행 제외 → 결과를 구글 시트에 기록합니다.

1) Code.gs

/** ===== 설정 ===== * 1) 실행 전 '스크립트 속성'에 아래 키를 저장하세요. * NAVER_CLIENT_ID, NAVER_CLIENT_SECRET * (앱스스클: 상단 톱니바 > 프로젝트 설정 > 스크립트 속성) */ const PROP = PropertiesService.getScriptProperties(); const CLIENT_ID = PROP.getProperty('NAVER_CLIENT_ID'); const CLIENT_SECRET = PROP.getProperty('NAVER_CLIENT_SECRET'); const API_URL = 'https://openapi.naver.com/v1/search/shop.json'; const MAX_TOTAL = 1000; const MAX_PER_REQUEST = 100; /** 웹앱 진입 (index.html 렌더) */ function doGet() { return HtmlService.createHtmlOutputFromFile('index') .setTitle('Naver Shopping Crawler'); } /** 공용 유틸: 태그/엔티티 정리 */ function cleanText(s) { if (!s) return ''; // <b> 태그 및 기타 태그 제거 s = s.replace(/<\/?b>/gi, '').replace(/<[^>]+>/g, ''); // HTML 엔티티 디코딩 return s.replace(/&amp;/g,"&") .replace(/&lt;/g,"<") .replace(/&gt;/g,">") .replace(/&quot;/g,'"') .replace(/&#39;/g,"'"); } /** 공용 유틸: 영문/숫자/언더스코어 슬러그 */ function slugifyAscii(text) { return (text || 'query') .toLowerCase() .replace(/[^a-z0-9]+/g, '_') .replace(/_+/g, '_') .replace(/^_+|_+$/g, ''); } /** 핵심: 네이버 쇼핑 검색 + 시트 쓰기 */ function fetchShoppingToSheet(query, totalCount) { if (!CLIENT_ID || !CLIENT_SECRET) { throw new Error('스크립트 속성에 NAVER_CLIENT_ID / NAVER_CLIENT_SECRET를 설정하세요.'); } if (!query) throw new Error('검색 키워드는 비어 있을 수 없습니다.'); totalCount = Math.max(1, Math.min(Number(totalCount) || 0, MAX_TOTAL)); const headers = { 'X-Naver-Client-Id': CLIENT_ID, 'X-Naver-Client-Secret': CLIENT_SECRET }; const out = []; let fetched = 0; while (fetched < totalCount) { const remaining = totalCount - fetched; const display = Math.min(MAX_PER_REQUEST, remaining); const start = fetched + 1; // 1-base, 최대 1000 const params = { query: query, display: display, start: start, sort: 'sim', // 요구사항: 중고/렌탈/해외직구·구매대행 제외 exclude: 'used:rental:cbshop' }; const url = API_URL + '?' + toQuery(params); const res = UrlFetchApp.fetch(url, { method: 'get', headers: headers, muteHttpExceptions: true }); const code = res.getResponseCode(); if (code !== 200) { throw new Error('네이버 API 오류: HTTP ' + code + ' / ' + res.getContentText()); } const data = JSON.parse(res.getContentText()); const items = (data && data.items) || []; if (!items.length) break; items.forEach(it => { out.push([ cleanText(it.title), it.link || '', it.image || '', it.lprice || '', it.hprice || '', it.mallName || '', it.brand || '', it.maker || '', it.category1 || '', it.category2 || '', it.category3 || '', it.category4 || '' ]); fetched++; }); // API 예의상 살짝 휴식 Utilities.sleep(120); } // === 시트에 기록 === const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheetName = 'naver_shopping_' + slugifyAscii(query) + '_' + Utilities.formatDate(new Date(), Session.getScriptTimeZone(), 'yyyyMMdd_HHmmss'); const sh = ss.insertSheet(sheetName); const header = [ 'title','link','image','lprice','hprice','mallName', 'brand','maker','category1','category2','category3','category4' ]; sh.getRange(1,1,1,header.length).setValues([header]); if (out.length) { sh.getRange(2,1,out.length, header.length).setValues(out); } // 자동 너비 sh.autoResizeColumns(1, header.length); return { sheetUrl: ss.getUrl(), sheetName: sheetName, rowCount: out.length }; } /** 쿼리스트링 유틸 */ function toQuery(obj) { return Object.keys(obj) .map(k => encodeURIComponent(k) + '=' + encodeURIComponent(String(obj[k]))) .join('&'); }

2) index.html

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Naver Shopping Crawler</title> <style> body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial; margin: 2rem; } label { display:block; margin: .5rem 0 .25rem; } input[type="text"], input[type="number"] { width: 320px; padding: .5rem; } button { padding: .6rem 1rem; margin-top: 1rem; } .log { margin-top: 1rem; white-space: pre-wrap; } </style> </head> <body> <h2>네이버 쇼핑 수집 (중고·렌탈·해외직구/구매대행 제외)</h2> <label>검색 키워드</label> <input id="q" type="text" placeholder="예: 딸기잼"> <label>수집 개수 (최대 1000)</label> <input id="n" type="number" min="1" max="1000" value="200"> <div><button onclick="run()">수집 시작</button></div> <div class="log" id="log"></div> <script> function log(msg) { document.getElementById('log').textContent = msg; } function run() { const q = document.getElementById('q').value.trim(); const n = Number(document.getElementById('n').value || 0); if (!q) { log('검색 키워드를 입력하세요.'); return; } if (!n || n < 1 || n > 1000) { log('수집 개수는 1~1000 사이 정수여야 합니다.'); return; } log('수집 중... 잠시만 기다려주세요.'); google.script.run .withSuccessHandler(res => { log(`완료! ${res.rowCount}건 기록됨\n시트: ${res.sheetName}\n\n스프레드시트 열기:\n${res.sheetUrl}`); }) .withFailureHandler(err => { log('오류: ' + (err && err.message ? err.message : err)); }) .fetchShoppingToSheet(q, n); } </script> </body> </html>

배포/사용 방법 (요약)

1.
Apps Script 새 프로젝트 → 위의 Code.gs, index.html 추가.
2.
스크립트 속성
NAVER_CLIENT_ID
NAVER_CLIENT_SECRET 입력.
3.
웹앱 배포: 배포 ▶ 웹앱 → "앱 실행: 본인", "접근권한: 본인(또는 조직)" → 배포 URL 열기.
4.
웹앱에서 키워드/수량 입력 → 실행 → 현재 스프레드시트naver_shopping_<slug>_<timestamp> 시트로 결과가 저장됩니다.
참고
API 파라미터: display ≤ 100, start ≤ 1000. 위 코드는 이를 고려해 루프 호출합니다.
제외 옵션: exclude=used:rental:cbshop (중고/렌탈/해외직구·구매대행 제외).
정렬은 sim(정확도). 최신순은 date로 교체하세요(Code.gssort 값).
구글 Sheet > Apps Script 오픈
Code.gs와 index.html 생성 및 GPT 코드 ctrl c, ctrl v
스크립트 속성에 NAVER_CLIENT_ID, NAVER_CLIENT_SECRET 삽입하는 방법
이렇게 하면 소스 코드에 ID저장되지 않아서 보안상 더 안전함
Apps Script 저장 > 실행
버그 발생시에는 오류(error) 내용을 카피해서 GPT에게 그대로 문의
Apps Script 배포
웹 앱 + 액세스 권한 설정
검색 화면 : 웹 앱 URL
위 URL 접속 > '블루투스 이어폰' 검색 예시
스프레드시트 열기 (맨 처음 시작했던 스프레드시트와 동일함)
추가 데이터 분석 진행
기타 응용
index.html > 더 예쁘고 깔끔하고, 고도화(조건화) 가능
중고/렌탈/해외직구·구매대행
정확도, 최신순
네이버 API : 로그인 API, 서비스 API 등 다양한 API를 오픈해 두고 있음
다른 검색 API 활용 가능
검색 API 외에 데이터랩 API
데이터랩 API 활용
Contact : azureguy@empal.com / azureguy@cau.ac.kr