GCP/Apps Script

Apps Script로 공공데이터 포털 openAPI 데이터를 매일 Telegram으로 받기

whistory 2022. 12. 29. 10:10
반응형

 

 

 

매일 주택청약 확인을 위해 홈페이지를 들어갔다.

https://www.applyhome.co.kr/ai/aib/selectSubscrptCalenderView.do#a

 

매일 홈페이지를 들어가지 않고, 공공데이터 포털에서 제공하는 데이터를 Telegram 메세지로 받아보도록 해봤다.

 

 

1. telegram bot 설정하기

BotFather 을 검색하고 인증되어 있는 BotFather을 선택한다.

/start 를 입력하고,

/newbot 으로 bot을 생성한다.

생성할 bot 이름을 입력한다.

입력하면 토큰을 발 받을 수 있다.

 

 

 

getUpdates url 을 호출하면 빈값을 반환한다.

https://api.telegram.org/bot${token}/getUpdates

{"ok":true,"result":[{}]}

봇을 검색하고, 봇에 메세지를 입력한 후

url을 다시 호출하면 chat_id 값을 얻을 수 있다.

https://api.telegram.org/bot${token}/getUpdates

{"ok":true,"result":[
...
"chat":{"id":여기가 chat id ,"first_name":"\\ud718","last_name":"\\uc11c","username":"whiseung","type":"private"}
...
]}
/**
 * Telegram send messages
 */
function sendTelegramMsg(message) {
  message = "봇 메시지 테스트";
  const token = 'tocken here';
  const chat_id = 'chatid here'
  const url = `https://api.telegram.org/bot${token}/sendmessage?chat_id=${chat_id}&text=${message}`;
  const response = UrlFetchApp.fetch(url);
  console.log(response.getResponseCode());
}

 

 

 

2. 주택청약 데이터 가져오기

공공데이터 포털에서 openAPI 활용 신청을 누르고, key를 발급 받아 사용한다.

“한국부동산원_청약홈 분양정보 조회 서비스”

공공데이터 포털

 

공공데이터 포털

국가에서 보유하고 있는 다양한 데이터를『공공데이터의 제공 및 이용 활성화에 관한 법률(제11956호)』에 따라 개방하여 국민들이 보다 쉽고 용이하게 공유•활용할 수 있도록 공공데이터(Datase

www.data.go.kr

openAPI를 호출해 데이터를 확인해본다.

/**
 * 청약홈 분양정보 조회 
 */
function getLhData() {
  const serviceKey = "service key here";
  const returnType = "JSON"; // JSON || XML
  const cond_area = "서울";

  const sDay = getTodayDate("start");
  const eDay = getTodayDate();

  const url = "<https://api.odcloud.kr/api/ApplyhomeInfoDetailSvc/v1/getAPTLttotPblancDetail?page=1&perPage=10&returnType=>"+ returnType 
            + "&cond[SUBSCRPT_AREA_CODE_NM::EQ]="+ cond_area + "&cond[RCRIT_PBLANC_DE::LTE]="+ eDay + "&cond[RCRIT_PBLANC_DE::GTE]="
            + sDay + "&serviceKey=" + serviceKey;

  const response = UrlFetchApp.fetch(url, { method : "GET",
                                            header:{
                                              "contentType" : "application/json"
                                            }
                                          });

  const json = response.getContentText();
  const returndData = JSON.parse(json);
  const datas = returndData.data;

  var returnObj = new Array();
  for ( i in datas ) {
    console.log(datas[i]);
  }
}

청약홈의 데이터를 확인해, 사용할 데이터만 추려본다.

{ BSNS_MBY_NM: '둔촌주공아파트주택재건축정비사업조합',
  CNSTRCT_ENTRPS_NM: '현대건설㈜, HDC현대산업개발㈜, ㈜대우건설, 롯데건설㈜',
  CNTRCT_CNCLS_BGNDE: '2023-01-03',
  CNTRCT_CNCLS_ENDDE: '2023-01-17',
  GNRL_RNK1_CRSPAREA_RCEPT_PD: '2022-12-06',
  GNRL_RNK1_ETC_AREA_RCPTDE_PD: '2022-12-07',
  GNRL_RNK1_ETC_GG_RCPTDE_PD: null,
  GNRL_RNK2_CRSPAREA_RCEPT_PD: '2022-12-08',
  GNRL_RNK2_ETC_AREA_RCPTDE_PD: '2022-12-08',
  GNRL_RNK2_ETC_GG_RCPTDE_PD: null,
  HMPG_ADRES: '<http://www.olympicpark-foreon.com>',
  HOUSE_DTL_SECD: '01',
  HOUSE_DTL_SECD_NM: '민영',
  HOUSE_MANAGE_NO: 2022000846,
  HOUSE_NM: '올림픽파크 포레온',
  HOUSE_SECD: '01',
  HOUSE_SECD_NM: 'APT',
  HSSPLY_ADRES: '서울특별시 강동구 둔촌1동 170-1 일대',				-- 공급위치
  HSSPLY_ZIP: '05409',
  IMPRMN_BSNS_AT: 'Y',
  LRSCL_BLDLND_AT: 'N',
  MDAT_TRGET_AREA_SECD: 'Y',
  MDHS_TELNO: '024749505',
  MVN_PREARNGE_YM: '202501',
  NPLN_PRVOPR_PUBLIC_HOUSE_AT: 'N',
  PARCPRC_ULS_AT: 'Y',
  PBLANC_NO: 2022000846,
  PBLANC_URL: '<https://www.applyhome.co.kr/ai/aia/selectAPTLttotPblancDetail.do?houseManageNo=2022000846&pblancNo=2022000846>',
  PRZWNER_PRESNATN_DE: '2022-12-15',
  PUBLIC_HOUSE_EARTH_AT: 'N',
  RCEPT_BGNDE: '2022-12-05',		-- 청약시작
  RCEPT_ENDDE: '2022-12-08',		-- 청약종료
  RCRIT_PBLANC_DE: '2022-11-25',	-- 모집공고일
  RENT_SECD: '0',
  RENT_SECD_NM: '분양주택',
  SPECLT_RDN_EARTH_AT: 'Y',
  SPSPLY_RCEPT_BGNDE: '2022-12-05',
  SPSPLY_RCEPT_ENDDE: '2022-12-05',
  SUBSCRPT_AREA_CODE: '100',
  SUBSCRPT_AREA_CODE_NM: '서울',
  TOT_SUPLY_HSHLDCO: 4786 			-- 공급규모
}

 

 

 

/**
 * 청약홈 분양정보 조회 
 */
function getLhData() {
  const serviceKey = "service key here";
  const returnType = "JSON"; // JSON || XML
  const cond_area = ["서울", "경기"];

  const sDay = getTodayDate("start");
  const eDay = getTodayDate();

  for ( j in cond_area ) {
    const url = "<https://api.odcloud.kr/api/ApplyhomeInfoDetailSvc/v1/getAPTLttotPblancDetail?page=1&perPage=10&returnType=>"+ returnType 
              + "&cond[SUBSCRPT_AREA_CODE_NM::EQ]="+ cond_area[j] + "&cond[RCRIT_PBLANC_DE::LTE]="+ eDay + "&cond[RCRIT_PBLANC_DE::GTE]="
              + sDay + "&serviceKey=" + serviceKey;

    const response = UrlFetchApp.fetch(url, {
      method : "GET",
      header:{
        "contentType" : "application/json"
      }
    });

    const json = response.getContentText();
    const returndData = JSON.parse(json);
    const datas = returndData.data;

    for ( i in datas ) {
      var message = `${cond_area[j]}지역 주택청약 정보 (${parseInt(i)+1})\\r\\n\\r\\n`;
      var data = new Object();
      data.CNSTRCT_ENTRPS_NM = datas[i].CNSTRCT_ENTRPS_NM;
      data.HMPG_ADRES = datas[i].HMPG_ADRES;
      data.HOUSE_DTL_SECD_NM = datas[i].HOUSE_DTL_SECD_NM;
      data.HOUSE_NM = datas[i].HOUSE_NM;
      data.HOUSE_SECD_NM = datas[i].HOUSE_SECD_NM;
      data.HSSPLY_ADRES = datas[i].HSSPLY_ADRES;
      data.RCEPT_BGNDE = datas[i].RCEPT_BGNDE;
      data.RCEPT_ENDDE = datas[i].RCEPT_ENDDE;
      data.RENT_SECD_NM = datas[i].RENT_SECD_NM;

      message += `명칭\\t: ${datas[i].HOUSE_NM}(${datas[i].HOUSE_DTL_SECD_NM} - ${datas[i].RENT_SECD_NM})\\r\\n지번\\t: ${datas[i].HSSPLY_ADRES}\\r\\n건설사\\t: ${datas[i].CNSTRCT_ENTRPS_NM}\\r\\n청약시작\\t: ${datas[i].RCEPT_BGNDE}\\r\\n청약종료\\t: ${datas[i].RCEPT_ENDDE}\\r\\n공급규모\\t: ${datas[i].TOT_SUPLY_HSHLDCO}세대\\r\\n홈페이지\\t: ${datas[i].HMPG_ADRES}\\r\\n\\r\\n\\r\\n`;
      console.log(message);
    }

  }
}

/**
 * Telegram send messages
 */
function sendTelegramMsg(message) {
  const token = 'tocken here';
  const chat_id = 'chat id here'
  const url = `https://api.telegram.org/bot${token}/sendmessage?chat_id=${chat_id}&text=${message}`;
  const response = UrlFetchApp.fetch(encodeURI(url));
  console.log(response.getResponseCode());
}

/**
 * Date (KST) return
 * @param {string} gubun  = 구분자 (Default / BigQuery)
 */
function getTodayDate(gubun) {
  var gubunValue = 0;
  if ( gubun == "start" ) {
    gubunValue = -(86400000 * 12);
  }

  const curr          = new Date();
  const utc           = curr.getTime() + gubunValue + (curr.getTimezoneOffset() * 60 * 1000);
  const KR_TIME_DIFF  = 9 * 60 * 60 * 1000;
  const today         = new Date(utc + (KR_TIME_DIFF));

  const dateConcat  = "-";
  const date        = today.getFullYear() + dateConcat + lpad((today.getMonth()+1), 2, '0') + dateConcat + lpad(today.getDate(), 2, '0');
  return date;
}
/**
 * lpad
 * @param {string}  str     = 원 문자열
 * @param {int}     padLen  = 최대 채우고자 하는 길이
 * @param {string}  padStr  = 채우고자하는 문자(char)
 */
function lpad(str, padLen, padStr) {
  if ( padStr.length > padLen ) {
    console.log("오류 : 채우고자 하는 문자열이 요청 길이보다 큽니다");
    return str;
  }
  str     += "";
  padStr  += "";
  while (str.length < padLen) {
    str = padStr + str;
  }
  str = str.length >= padLen ? str.substring(0, padLen) : str;
  return str;
}

 

메시지 전송 횟수를 줄이기 위해 한번에 보내려고 했는데, urlfatch length limit에 걸려 버렸다.

그냥 메세지 한번에, 정보 하나씩 보내야 겟다.

 

 

 

3. Time-driven trigger 설정

테스트로 1분단위로 설정해본다.

1분단위로 정상적인 데이터 수집을 확인했다.

 

 

 

이제 매일 아침에 알림을 받도록 설정하면 매일 아침 정보를 받을 수 있다.

 

 

 

완료

/**
 * 청약홈 분양정보 조회 
 */
function getLhData() {
  const serviceKey = "service key here";
  const returnType = "JSON"; // JSON || XML
  const cond_area = ["서울", "경기"];

  const sDay = getTodayDate("start");
  const eDay = getTodayDate();

  const start_message = `====== ${eDay} 시작 ======`;
  sendTelegramMsg(start_message);

  for ( j in cond_area ) {
    const url = "<https://api.odcloud.kr/api/ApplyhomeInfoDetailSvc/v1/getAPTLttotPblancDetail?page=1&perPage=10&returnType=>"+ returnType 
              + "&cond[SUBSCRPT_AREA_CODE_NM::EQ]="+ cond_area[j] + "&cond[RCRIT_PBLANC_DE::LTE]="+ eDay + "&cond[RCRIT_PBLANC_DE::GTE]="
              + sDay + "&serviceKey=" + serviceKey;

    const response = UrlFetchApp.fetch(url, {
      method : "GET",
      header:{
        "contentType" : "application/json"
      }
    });

    const json = response.getContentText();
    const returndData = JSON.parse(json);
    const datas = returndData.data;

    var returnObj = new Array();
    for ( i in datas ) {
      var message = `${cond_area[j]}지역 주택청약 정보 (${parseInt(i)+1})\\r\\n\\r\\n`;
      var data = new Object();
      data.CNSTRCT_ENTRPS_NM = datas[i].CNSTRCT_ENTRPS_NM;
      data.HMPG_ADRES = datas[i].HMPG_ADRES;
      data.HOUSE_DTL_SECD_NM = datas[i].HOUSE_DTL_SECD_NM;
      data.HOUSE_NM = datas[i].HOUSE_NM;
      data.HOUSE_SECD_NM = datas[i].HOUSE_SECD_NM;
      data.HSSPLY_ADRES = datas[i].HSSPLY_ADRES;
      data.RCEPT_BGNDE = datas[i].RCEPT_BGNDE;
      data.RCEPT_ENDDE = datas[i].RCEPT_ENDDE;
      data.RENT_SECD_NM = datas[i].RENT_SECD_NM;

      message += `명칭\\t: ${datas[i].HOUSE_NM}(${datas[i].HOUSE_DTL_SECD_NM} - ${datas[i].RENT_SECD_NM})\\r\\n지번\\t: ${datas[i].HSSPLY_ADRES}\\r\\n건설사\\t: ${datas[i].CNSTRCT_ENTRPS_NM}\\r\\n청약시작\\t: ${datas[i].RCEPT_BGNDE}\\r\\n청약종료\\t: ${datas[i].RCEPT_ENDDE}\\r\\n공급규모\\t: ${datas[i].TOT_SUPLY_HSHLDCO}세대\\r\\n홈페이지\\t: ${datas[i].HMPG_ADRES}\\r\\n\\r\\n\\r\\n`;

      returnObj[i] = data;

      // console.log(datas[i]);
      console.log(message);

      sendTelegramMsg(message);
    }

  }
  const end_message = `====== ${eDay} 끝 ======`;
  sendTelegramMsg(end_message);
}

/**
 * Telegram send messages
 */
function sendTelegramMsg(message) {
  const token = 'tocken here';
  const chat_id = 'chat id here'
  const url = `https://api.telegram.org/bot${token}/sendmessage?chat_id=${chat_id}&text=${message}`;
  const response = UrlFetchApp.fetch(encodeURI(url));
  console.log(response.getResponseCode());
}

/**
 * Date (KST) return
 * @param {string} gubun  = 구분자 (Default / BigQuery)
 */
function getTodayDate(gubun) {
  var gubunValue = 0;
  if ( gubun == "start" ) {
    gubunValue = -(86400000 * 12);
  }

  const curr          = new Date();
  const utc           = curr.getTime() + gubunValue + (curr.getTimezoneOffset() * 60 * 1000);
  const KR_TIME_DIFF  = 9 * 60 * 60 * 1000;
  const today         = new Date(utc + (KR_TIME_DIFF));

  const dateConcat  = "-";
  const date        = today.getFullYear() + dateConcat + lpad((today.getMonth()+1), 2, '0') + dateConcat + lpad(today.getDate(), 2, '0');
  return date;
}
/**
 * lpad
 * @param {string}  str     = 원 문자열
 * @param {int}     padLen  = 최대 채우고자 하는 길이
 * @param {string}  padStr  = 채우고자하는 문자(char)
 */
function lpad(str, padLen, padStr) {
  if ( padStr.length > padLen ) {
    console.log("오류 : 채우고자 하는 문자열이 요청 길이보다 큽니다");
    return str;
  }
  str     += "";
  padStr  += "";
  while (str.length < padLen) {
    str = padStr + str;
  }
  str = str.length >= padLen ? str.substring(0, padLen) : str;
  return str;
}
반응형