인공지능 (AI) 따라잡기

[국토교통부 오픈 API] 전국 아파트 실거래 현황이 구글시트에 '쏙쏙'

MoneyManager 2025. 7. 13. 03:07
728x90

IMAGEFX를 통해 생성한 AI 이미지 입니다.

코딩 하나도 몰랐던 내가,

아파트 실거래가 자동화에 성공!!!

(ChatGPT  고마워^^)

 

👩‍💻 "코딩? 나랑 상관없는 줄 알았어요.

근데 ChatGPT랑 하니까 이게 되네요!"

 

 오전에 지하철로 이동하다가

문득 아파트 실거래가를

쉽게 조회할 수 있게

해보고 싶었어요. 

토요일 저녁 집에 돌아와서

chatGPT랑 작업했고  

아파트 실거래 데이터를

구글시트로 구현하는데 성공했네요.  

 

물론 국토교통부 홈페이지에서

확인하면 되는 일이지만

그래도 구글시트로

바로 가져오면

여러가지 쓸모가

많을 것 같네요. 


이 글은 "나도 할 수 있을까?"

고민하고 계신 분들을 위해 써보는 후기

입니다.

 

코딩 완전 초보였던 제가

ChatGPT의 도움을 받아

구글시트를 통해

국토교통부 API로

아파트 거래동향을

간편하게 조회하는 과정

공유합니다. 


 

우선 화면 구성은 좀 촌스럽지만

첫 화면이니

차차 개선해 나가면 되겠죠   

 

기본 구성은 간결하게 

노란색 입력 부분과

빨간색 실행 버튼만 있습니다. 

 

A1 :  11680 (5자리 행정동 코드)  또는 11 (서울 전체)

C1 :  검색 시작월

D1 :  검색 종료월 

 

7월중 서울시 전체 실거래 데이터를 뽑아볼께요.

 

 

11번은 서울 전체를 의미해요.

 

  7월 13일 현재

7월 서울 전체 거래는

231건이 구글시트로 쏙

들어왔습니다. 

 

헉~~

7월 최고가는

압구정동  현대8차

83억!!!

 

 

만들게 된 배경은

실거래가 매번 검색하기 귀찮기 때문

 

부동산이든 주식이든, 데이터는 많지만

내가 원하는 정보만 뽑아보는 건 참 어렵죠.

저는 평소 아파트 실거래가에 관심이 많았는데,

 

매번 검색하고, 엑셀에 붙여넣고… 너무 비효율적이었어요.

 

그때 문득 생각난 게 "이거 자동으로 안 되나?"였고,

ChatGPT에게 물어봤습니다.


🤖 Step 1. ChatGPT에게 물어봤어요

 

 

제가 처음 던진 질문은 이랬어요.

 

👉 "국토교통부 아파트 실거래가 OPEN API를 구글시트에서 활용하는 코드 만들어"

 

그러자 정말… 놀랍게도 필요한 절차부터 코드, 설명까지 다 알려주네요.

 

 "이대로 따라만 하세요" 스타일로요!

인증키 발급 등

사전 준비는 필요하네요구글 계정 (구글시트용)

 

공공데이터포털 회원가입

실거래가 API 신청

인증키 발급


📜 Step 2. ChatGPT가 알려준 코드 복사 붙여넣기

구글시트 → 확장 프로그램 → 앱스 스크립트

 

ChatGPT와 코드 만들고 수정하기를

여러번 해서 일단 결과값이 나왔습니다.    

다만, 코드에서 인증키만 일부 가렸습니다. 

 

왠지 코드가 초보자 티가 나는것 같아요.  

이건 차근차근 업그레이드 해야겠어요. 

 

특히, 행정구역 넣는 부분을

쭉 나열한 부분은 개선해야겠어요 

 

 

아래 코드에 본인의 인증키만 넣어서

구글시트-확장 프로그램-앱스 스크립트에

넣으면 됩니다. 

 

처음에는 구글 계정에서

스크립트 사용하는 허가 과정이 있기는 합니다. 

 

function fetchRealEstateFullFields() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getActiveSheet();

  const regionInput = sheet.getRange('A1').getValue().toString().trim();
  const startYmd = sheet.getRange('C1').getValue().toString().trim();
  const endYmd = sheet.getRange('D1').getValue().toString().trim();

  if (!regionInput || !startYmd || !endYmd) {
    SpreadsheetApp.getUi().alert('A1(지역코드), C1(시작월), D1(종료월)을 입력해주세요.');
    return;
  }

  const API_KEY = 'EiSwcNcFmNxdrxxxxxxxxxxxxxxxxxxxxxxxxxLyeThY9HnCpqzxxvXNQ%3D%3D';
  const BASE_URL = 'https://apis.data.go.kr/1613000/RTMSDataSvcAptTrade/getRTMSDataSvcAptTrade';
  const monthList = generateMonthList(startYmd, endYmd);
  const allLawdCodes = getLawdCodesFromSheet();

  const validLawdCodes = new Set();
  if (regionInput.length === 2) {
    allLawdCodes.forEach(code => {
      if (code.startsWith(regionInput)) validLawdCodes.add(code);
    });
  } else if (regionInput.length === 5) {
    validLawdCodes.add(regionInput);
  } else {
    SpreadsheetApp.getUi().alert('올바른 시·도(2자리) 또는 시군구(5자리) 코드를 A1에 입력해주세요.');
    return;
  }

  sheet.getRange('A3:R10000').clearContent();
  sheet.getRange('A2:R2').setValues([[
    '아파트명', '동번호', '지번', '법정동', '건축년도', '전용면적(㎡)', '층', '거래금액(만원)', '거래일',
    '매수자구분', '매도자구분', '거래유형', '공인중개소', '토지임차구분', '등기접수일', '시군구코드', '계약해제유형', '계약해제일'
  ]]);

  let row = 3;
  for (let lawdCd of validLawdCodes) {
    for (let yyyymm of monthList) {
      const url = `${BASE_URL}?serviceKey=${API_KEY}&LAWD_CD=${lawdCd}&DEAL_YMD=${yyyymm}`;

      try {
        const response = UrlFetchApp.fetch(url, {
          method: 'get',
          contentType: 'application/xml',
          muteHttpExceptions: true
        });

        if (response.getResponseCode() !== 200) continue;

        const xml = XmlService.parse(response.getContentText());
        const items = xml.getRootElement().getChild('body').getChild('items').getChildren('item');

        for (let item of items) {
          const getText = tag => (item.getChildText(tag) || '').trim();

          const aptNm = getText('aptNm');
          const aptDong = getText('aptDong');
          const jibun = getText('jibun');
          const umdNm = getText('umdNm');
          const buildYear = getText('buildYear');
          const area = getText('excluUseAr');
          const floor = getText('floor');
          const price = getText('dealAmount');

          const dealYear = getText('dealYear');
          const dealMonth = getText('dealMonth').padStart(2, '0');
          const dealDay = getText('dealDay').padStart(2, '0');
          const dealDate = `${dealYear}-${dealMonth}-${dealDay}`;

          const buyerGbn = getText('buyerGbn');
          const slerGbn = getText('slerGbn');
          const dealingGbn = getText('dealingGbn');
          const agent = getText('estateAgentSggNm');
          const leaseGbn = getText('landLeaseholdGbn');
          const rgstDate = getText('rgstDate');
          const sggCd = getText('sggCd');
          const cdealType = getText('cdealType');
          const cdealDay = getText('cdealDay');

          sheet.getRange(row, 1, 1, 18).setValues([[
            aptNm, aptDong, jibun, umdNm, buildYear, area, floor, price, dealDate,
            buyerGbn, slerGbn, dealingGbn, agent, leaseGbn, rgstDate, sggCd, cdealType, cdealDay
          ]]);
          row++;
        }

      } catch (err) {
        Logger.log(`오류: LAWD_CD=${lawdCd}, DEAL_YMD=${yyyymm}, 메시지=${err.message}`);
      }
    }
  }

  SpreadsheetApp.getUi().alert(`데이터 수집 완료! 총 ${row - 3}건의 거래를 불러왔습니다.`);
}

function generateMonthList(startYmd, endYmd) {
  const startYear = parseInt(startYmd.substring(0, 4), 10);
  const startMonth = parseInt(startYmd.substring(4), 10);
  const endYear = parseInt(endYmd.substring(0, 4), 10);
  const endMonth = parseInt(endYmd.substring(4), 10);

  const result = [];
  for (let y = startYear; y <= endYear; y++) {
    const mStart = (y === startYear) ? startMonth : 1;
    const mEnd = (y === endYear) ? endMonth : 12;
    for (let m = mStart; m <= mEnd; m++) {
      result.push(`${y}${String(m).padStart(2, '0')}`);
    }
  }
  return result;
}

function getLawdCodesFromSheet() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getActiveSheet();
  const range = sheet.getRange('Z3:AA274').getValues();
  const codes = [];
  for (let row of range) {
    for (let val of row) {
      const str = val.toString().trim();
      if (str.length === 5) {
        codes.push(str);
      }
    }
  }
  return codes;
}

📷 이미지1: 구글시트에서 앱스스크립트 실행하는 화면 캡처


 

💬 왕초보에게 꼭 해주고 싶은 말

저 진짜 코딩 모르는데 ChatGPT가

이해할 수 있을 때까지 쉽게 설명해주

오류 나면 왜 그런지 알려주고

수정할 코드까지 제안해 주면서

만들었습니다.  

 

저 같은 초보도 가능하니까, 여러분도 꼭 도전해보세요!


🙌 데이터는 이제 누구나 다룰 수 있어요

예전엔 전문가들만 다루던 데이터 분석도

지금은 ChatGPT와 함께라면

누구나 도전할 수 있는 시대입니다.

 

구독해주시고 궁금한 점 있으시면

댓글 남겨주세요.

 

728x90