이 멋진 매크로에 스케쥴러를!
가끔씩 매번 반복해야 하지만 단순하면서도 귀찮은 일이 있다.
이번 프로그램은 그런 일을 자동화 해주는 것인데 대표적인 예로
군대
입대를 한 친구를 위해 정기적으로 편지를 써 주는 일 이다!!
듣기만 해도 토가 절로 나온다.
사용된 기술 스택
- Firebase - Realtime Database, Functions, Hosting
- Vue.js -
2.5.11
- Node.js -
8.16.2
프로젝트 구조
핵심 기능 설명
Cloud Scheduler
구글 클라우드에서 제공해주는 스케쥴러 서비스로 unix-cron
형식의 정해진 시간대에 반복적인 작업을 수행 할 수 있게 되는데 이 때 Cloud functions 의 특정 API 를 HTTP 요청으로 보내게 설정이 가능하다.
예시에서는 0 */6 * * *
로 설정해두어 매일 6시간마다 0분이 될 경우 특정 HTTP URL 에 POST 메소드의 HTTP 요청을 하게 된다.
Flow
Cloud Scheduler로 부터 HTTP 요청을 받았을 경우 Cloud Functions 에서는 더 캠프를 통해 군인에게 편지를 작성해야 하는데 그 과정은 다음과 같다.
더 캠프 API 조사
Chrome 브라우저의 개발자 도구를 이용하면 Network 탭에서 다양한 네트워크 요청들을 확인 할 수 있는데 이 중 필요한 데이터를 응답 데이터를 보면서 찾아 내면 된다. 광고가 많은 사이트일 경우 요청기록이 많아 잦기가 힘들어질 수 도 있지만, 가끔씩은 노가다도 나름 할만 하다.
더 캠프 로그인
return new Promise((resolve, reject) => {
const request = require('request');
const options = {
uri: 'https://www.thecamp.or.kr/login/loginA.do',
method: 'POST',
form: {
state: 'email-login',
autoLoginYn: 'N',
userId: thecampInfo.email,
userPwd: thecampInfo.password
}
}
request.post(options, (err,httpResponse,body) => {
if (err) {
reject(new Error(`Error while sign in ${err.message}`))
}
const result = JSON.parse(body);
if (result.resultCd === '0000') {
const cookie = httpResponse.headers['set-cookie'].join('; ');
resolve(cookie);
} else {
reject(new Error(`Error while sign in ${result.resultCd}`))
}
})
})
로그인 API 경로에 POST 메소드로 로그인 하되, 폼 데이터에 이메일, 패스워드를 보내면 JSON
응답과 함께 세션정보가 담긴 Cookie 가 반환된다.
이 세션 정보를 가지고 있다가 다른 API 를 호출할때 같이 보내면 정상 응답이 된다.
더 캠프 편지 목록 조회
return new Promise((resolve, reject) => {
const request = require('request');
const options = {
uri: 'https://www.thecamp.or.kr/consolLetter/selectConsolLetterA.do',
method: 'POST',
headers: {
Cookie: cookie
},
form: {
traineeMgrSeq: thecampInfo.traineeMgrSeq,
tempSaveYn: 'N',
_url: 'https://www.thecamp.or.kr/consolLetter/viewConsolLetterMain.do',
keepSearchConditionUrlKey: 'consolLetter'
}
}
request.post(options, (err, httpResponse, body) => {
if (err) {
reject(new Error(`Error while check letter list ${err.message}`))
}
console.log('Check letter list body ', body);
const result = JSON.parse(body);
if (result.resultCd === '0000') {
resolve(result.listResult.filter(i => i.nickname === myNickname));
} else {
reject(new Error(`Error while check letter list ${result.resultCd}`))
}
})
})
편지 목록 조회 API에 조회하려는 군인의 시스템 고유 번호를 폼에 넣어 보내면 JSON
형태의 편지 리스트와 내용이 같이 배열로 반환된다.
더 캠프 편지 작성
return new Promise((resolve, reject) => {
const request = require('request');
const options = {
uri: 'https://www.thecamp.or.kr/consolLetter/insertConsolLetterA.do',
method: 'POST',
headers: {
Cookie: cookie
},
form: {
boardDiv: 'sympathyLetter',
tempSaveYn: 'N',
sympathyLetterContent: `<p>${content}</p>`,
sympathyLetterSubject: `${thecampInfo.traineeName} 기 살리기 T-${lastCount}`,
traineeMgrSeq: thecampInfo.traineeMgrSeq,
}
}
request.post(options, (err, httpResponse, body) => {
if (err) {
reject(new Error(`Error while write letter ${err.message}`))
}
console.log('Write letter body ', body);
const result = JSON.parse(body);
if (result.resultCd === '0000') {
resolve(result.resultCd)
} else {
reject(new Error(`Error while write letter ${result.resultCd}`))
}
})
})
편지 API에 본문 내용과 제목을 폼에 넣어주면 전송 완료!
네이버 실검 크롤링 하기
편지를 쓸 때 아무 의미 없는 내용을 반복적으로 보내기엔 너무 스팸성이 강하니 트끌같이 남은 양심을 살려 네이버 실검을 보내주도록 하자.
군대 훈련소 안에선 인터넷과 완전히 단절되니 이정도도 상당히 고마울꺼라 믿는다.
return new Promise((resolve, reject) => {
const cheerio = require('cheerio');
const request = require('request');
const options = {
uri: 'https://datalab.naver.com/keyword/realtimeList.naver',
method: 'GET',
headers: {
accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
'accept-encoding': 'gzip, deflate, br',
'accept-language': 'en-US,en;q=0.9,ko;q=0.8',
'cache-control': 'no-cache',
referer: 'https://datalab.naver.com/local/trend.naver',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36'
}
}
request.get(options, (err,httpResponse,body) => {
if (err) {
reject(new Error(`Error while get naver keyword site ${err.message}`))
}
const $ = cheerio.load(body);
const realtimeKeywordListStr = $('div[class=list_group]').text().trim().replace(/\s/g, '');
console.log('keyworad list: ', realtimeKeywordListStr);
resolve(realtimeKeywordListStr);
})
})
크롤링이야 어려울 것 같지만 의외로 단순할 수 있다.
원하는 페이지의 HTML 을 다운 받고, 크롤링 라이브러리 (본문엔 cheerio
사용) 을 이용해 특정 영역의 데이터를 가져오면 되는데
이 역시 개발자 도구를 이용하면 된다.
네이버 실검의 DOM 을 까보면 div 태그의 list_group 이라는 스타일 클래스를 속성으로 가지고 있는 것을 알 수 있다.
$('div[class=list_group]').text()
이는 위와 같이 표현 될 수 있는데 실행하면 많은 띄어쓰기와 함께 텍스트가 추출되는 것을 확인 할 수 있다.
결과
우린 이제 정해진 시간마다 컴퓨터가 대신 군인에게 편지를 써 줄 수 있게 되었다. 이렇게 되면 나도 귀찮지 않으면서 군인 친구도 편지를 받아 매우 기뻐할 것이다.
번외
간단히 Vue.js 를 이용하여 웹으로 편지가 전달 되었는지, 작성되었는지 알 수 있는 대쉬보드를 제작해 볼 수도 있다.
전체 소스는 아래