이 멋진 매크로에 스케쥴러를!

3 minute read

가끔씩 매번 반복해야 하지만 단순하면서도 귀찮은 일이 있다.

이번 프로그램은 그런 일을 자동화 해주는 것인데 대표적인 예로

군대 입대를 한 친구를 위해 정기적으로 편지를 써 주는 일 이다!!

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/c330948d-7818-4d37-99ca-f507d55132a9/f29bfcadad0ebc3a1ce06fad8a1bb2d4.jpg

듣기만 해도 토가 절로 나온다.

사용된 기술 스택

  • Firebase - Realtime Database, Functions, Hosting
  • Vue.js - 2.5.11
  • Node.js - 8.16.2

프로젝트 구조

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/5a6a4de0-734e-48cf-90c8-14af2d5de22e/Untitled_Diagram_(1).jpg

핵심 기능 설명

Cloud Scheduler

구글 클라우드에서 제공해주는 스케쥴러 서비스로 unix-cron 형식의 정해진 시간대에 반복적인 작업을 수행 할 수 있게 되는데 이 때 Cloud functions 의 특정 API 를 HTTP 요청으로 보내게 설정이 가능하다.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/748ad9be-e2dd-4436-83f8-c44a244fcf42/sadfsadf.png

예시에서는 0 */6 * * * 로 설정해두어 매일 6시간마다 0분이 될 경우 특정 HTTP URL 에 POST 메소드의 HTTP 요청을 하게 된다.

Flow

Cloud Scheduler로 부터 HTTP 요청을 받았을 경우 Cloud Functions 에서는 더 캠프를 통해 군인에게 편지를 작성해야 하는데 그 과정은 다음과 같다.

a

더 캠프 API 조사

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/68369614-2b8d-49a4-ad9f-bee536000ace/AASDFSAFDA.png

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 사용) 을 이용해 특정 영역의 데이터를 가져오면 되는데

이 역시 개발자 도구를 이용하면 된다.

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/369db392-cbd1-4306-ac4f-e964da628846/asdfasfdsafafsdaf.png

네이버 실검의 DOM 을 까보면 div 태그의 list_group 이라는 스타일 클래스를 속성으로 가지고 있는 것을 알 수 있다.

$('div[class=list_group]').text()

이는 위와 같이 표현 될 수 있는데 실행하면 많은 띄어쓰기와 함께 텍스트가 추출되는 것을 확인 할 수 있다.

결과

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/f9509552-a17f-4d2f-a659-91f0c5a71091/thecamp_demo.png

우린 이제 정해진 시간마다 컴퓨터가 대신 군인에게 편지를 써 줄 수 있게 되었다. 이렇게 되면 나도 귀찮지 않으면서 군인 친구도 편지를 받아 매우 기뻐할 것이다.

번외

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/56b95579-2f1c-417f-9ab3-c49e063db7f7/asdfasfdafdsafads.png

간단히 Vue.js 를 이용하여 웹으로 편지가 전달 되었는지, 작성되었는지 알 수 있는 대쉬보드를 제작해 볼 수도 있다.

전체 소스는 아래

stories2/The-Camp-Letter

Categories:

Updated: