반응형
매일 주택청약 확인을 위해 홈페이지를 들어갔다.
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를 발급 받아 사용한다.
“한국부동산원_청약홈 분양정보 조회 서비스”
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;
}
반응형
'GCP > Apps Script' 카테고리의 다른 글
Apps Script로 Upbit api를 이용해 코인 시세를 매일 아침에 Telegram으로 조간 브리핑 받기 (0) | 2023.01.03 |
---|---|
Apps Script로 Google Sheets에서 Dropdown의 multi select(다중선택) 구현 (0) | 2023.01.02 |
Apps Script로 MSSQL 데이터를 분단위 trigger로 sync 유지하기 (0) | 2022.12.27 |
관리용 Apps Script로 여러개의 Google Sheets 템플릿 관리하기 (0) | 2022.12.21 |
Apps Script로 Google Sheets에서 보고서 양식의 조회저장 기능 구현 (0) | 2022.10.11 |