EtoC
백엔드 단기인턴 회고 본문
1. 프로젝트 소개
프로젝트 기간: 2022.12.08 ~ 2023.01.04
팀명: MSG
구성원: Front: 2명 /Back: 2명
목적:
정해진 기간동안 일정 시간마다 회사에 등록된 인플루언서의 광고를 키워드로 검색하여 순위권에있는지 확인하고, 그 스크린샷을 찍어 저장하는 API를 만들어 수동으로 하던 시스템을 자동화 하는것.
2. 프로젝트 기획
3. 프로젝트 결과물
4. 맡은 역할
1. 크롤링하고 스크린샷 찍기
- puppeteer를 사용하여 브라우저를 실행하고 새 페이지를 생성하기
처음에는 cheerio를 사용한 단순한 크롤링을 만들어보았다.
그런데 원하는 기능을 사용하려고하니 pupeteer를 사용해야했고 puppeteer 문서를 읽으면서 작성하였다.
puppeteer로 간단한 뉴스를 크롤링해보고 회사에서 받은 json 파일을 열어보았는데, 이게 뭐지..하고 멍때렸던게 기억난다.
당시 정말 어려웠던게 광고를 올린사이트를 다르게 들어가서 사용자가 입력안 여러개의 검색어를 어떻게 순차적으로 찾는가였다.
팀원분이 map 함수를 공부해보라 하셨고 공부후 적용하여 사용자가 입력한 검색어에따라 순차적으로 함수가 실행되게 바꾸었다.
const urlResult = (sns_type) => {
const paramArr = searchParam.split(",");
const url = paramArr.map((param) => {
const encodedParam = encodeURI(param);
if (sns_type === "BLOG") {
return {
uri: `https://search.naver.com/search.naver?where=view&sm=tab_jum&query=${encodedParam}`,
keyword: param,
};
} else {
return {
uri: `https://www.instagram.com/explore/tags/${encodedParam}/`,
keyword: param,
};
}
});
return url;
};
이제 원하는 데이터를 찾아야하는데 이때 태그를 타고 들어간다는게 뭔지 알았다.
종이에 하나하나 적어가면서 찾다가 개발자모드에서 경로 복사가 있다는것을 알았고 아래처럼 작성하였다.
그런데 프론트분이 중복되는 태그가 없음녀 태그만 써도 된다고해서 좀더 줄여볼 수 있었다.
let lists = $(
"#_inf_content_root > div > div.keyword_challenge_wrap._fadein_target > div.challenge_wrap > ul> li"
);
lists =
lists.length === 0
? $(
"#main_pack > section.sc_new.sp_influencer._inf_content_section._prs_ink_mik > div > div.keyword_challenge_wrap > div > ul > li"
)
: $(
"#_inf_content_root > div > div.keyword_challenge_wrap._fadein_target > div.challenge_wrap > ul> li"
);
const keyword = $("#nx_search_form > fieldset > div.greenbox")
.find("input")
.attr("value");
이후로는 naver와 instagram에맞는 함수를 작성하고 사용하여 각각 네이버 블로그와 인스타그램에서 정보를 추출하고,
반환된 결과를 sns_type에 따라 조건에 맞는 함수를 선택하여 결과를 반환하는 crawlingResult 함수를 작성하였다.
const naverCrawling = async ($) => {
const lists = $("li.bx._svp_item");
let result = [];
await lists.each((i, list) => {
// const influencer = $(list).find('a.name').text().trim();
const blogUrl = $(list)
.find("div.total_wrap.api_ani_send > div > a")
.attr("href");
result.push({ i, blogUrl });
});
return result;
};
const instagramCrawling = async ($) => {
const lists = $("div._aabd._aa8k._aanf");
let result = [];
await lists.each((i, list) => {
const url = $(list).find("a").attr("href");
const blogUrl = `https://www.instagram.com${url}`;
result.push({ i, blogUrl });
});
return result;
};
const crawlingResult = async (sns_type, $) => {
const bodyBuilder = {
BLOG: naverCrawling,
INSTAGRAM: instagramCrawling,
};
const body = await bodyBuilder[sns_type]($);
return body;
};
2. node 스케듈러
크롤링을 만들다보니 자연스럽게 스케듈러가 어떻게 작동하는지가 궁금해졌다.
const cron = require('node-cron');
const schedulerDao = require('../models/schedulerDao');
const crawlingService = require('../services/crawlingService');
const task = cron.schedule('0 0 * * *', async () => {
const today = new Date();
const waitingScheduler = await schedulerDao.getSchedulerDetailInfo(
`AND cj.state ='waiting'`
);
const workingScheduler = await schedulerDao.getSchedulerDetailInfo(
`WHERE cj.state ='working'`
);
for (const waiting of waitingScheduler) {
const startday = new Date(waiting.start_day);
const endday = new Date(waiting.end_day);
if (startday < today && endday > today) {
await schedulerDao.patchSchedulerWorking(waiting.idx);
}
}
for (const working of workingScheduler) {
const startday = new Date(working.start_day);
const endday = new Date(working.end_day);
if (startday < today && endday > today) {
await schedulerDao.updateRunCount(working.idx);
await crawlingService.start(
working.campaign_idx,
working.keyword,
working.sns_type,
working.idx,
working.posting_url
);
} else if (endday < today) {
schedulerDao.patchSchedulerEnd(working.idx);
}
}
});
module.exports = { task };
좋았던 점
0. 팀원들과 분위기
개인적으로 함께하고 싶은 분들과 팀이 되어서 너무 좋았다.
함께 모여서 간식먹으면서 개발하고, 함께 꾸중듣고, 프로젝트를 마치고 아쉬웠던점을 진지하게 하지만 기분상하지 않게 말씀해주셔서 정말 감사했다.
1. 처음으로 DOCS를 읽고 새로운것을 만들어 봄
일정시간마다 함수가 작동하여 페이지의 내용들을 긁어와서 비교하고 스크린샷을 찍으라는 업무를 배정받았을때 뭐가 뭔지 몰랐다.
인터넷에서 검색하니 그것을 크롤링이라 하는것을 알았다.
우선 간단한 크롤링만들기에 cheerio를 사용하면된다고해서 cheerio로 만들어보았는데 원하는 기능을 구현하기위해서는 pupperteer를 사용해야했다.
크롤링을 할때 원하는 정보를 가져오기위해서 html의 태그들을 파고 들어가야했는데 이 작업도 어려웠지만 원하는 정보를 가져와서 터미널에 띄울때 정말이지 희열을 느꼈다.
2. 실무에대해 많은 것을 배웠다
이번 3차프로젝트는 실제로 기업에서 업무를 배분받고 작업을 하였다.
첫 날 회사와 학원간의 시간착오로 인해 급하게 회사와 업무에대한 설명을 받았지만 CTO님께서 많은것을 알려주시려하는것을 느꼈다.
이후 프로젝트에대한 기획을 하였는데, CTO님께서 고려해야할것들이 많이 빠져있다는것을 알려주셨다.
생각보다 개발자가 고려해야할게 많다는것을 느꼈다.
그렇게 잘 모르겠는 부분들은 슬랙을 통해서 질문하고, 조언을 받으면서 기획을 진행했는데 거의 2주가 걸렸다.
학원에서는 이미 만들어진 사이트를 모델링하거나 조금 변형하는 정도여서 기획이 이렇게 어려운 것인줄 몰랐고, 사용자의 입장을 고려한 생각을정말 많이해야한다는 것을 느꼈다.
부족한 점
1. 자바스크립트 실력
크롤링을 하면서 제일 어려웠던 점이 어떻게 브라우저에서 입력된 복수의 키워드들을 하나씩 돌려가면서 검색하게 하는가였다.
하나씩 키워드를 하나에 하나의 창으로 열 수는 있었으나 한페이지에서 돌려가면서 검색하는 방법을 모르겠었다.
팀원분께 어떻게 해야할지 물어보았더니 map 함수를 쓰면 된다고 공부해보라는 조언을 받았다.
map함수를 돌려서 작동하는것을 볼때는 정말 신기했다.
자바스크립트 문법 공부 및 프로그래머스 꼭 풀자.
2. 모르겠는것을 빨리 말하지 않은것
실제 CTO님께서 맡기신 업무는 원하는 광고가 표시될때 스크린샷을찍고 그 광고가 있는 위치에 빨간색 체크 박스로 표시를 해서 이미지를 저장하는 것이였다.
node canvas를 사용해서 그림을 그릴 수는 있었으나, 어떻게 자동적으로 찍힌 스크린샷에 원하는 광고의 위치가 있는지 찾아서 그림을 그려야하는지를 알지 못했다.
이 문제로 끙끙앓고 있었는데이때문에 시간을 많이 끌렸다.
결국 3일을 시도하다가 CTO님께 말씀드리니 못하겠을때는 빨리 말해야한다고 말씀하셨다.
이 기능은 필수가 아닌 추가로 해주었으면 좋겠다고 생각하셨던 거라서 스크린샷만 찍을 수 있으면 안해도 된다고 하셨다.
또 크롤링을 하면서 scheduler를 모르겠으니 이해가 안가는 부분이 있었다.
스케듈러를 맡으신 다른 팀원분께 물어보고 작업을 하면되었는데, 귀찮게하고싶지않다는 생각에 혼자 스케듈러를 만들어서 작업해보았다.
내가 이 쪽에 함몰되어잇는 사이에 팀원분은 다른 업무까지 하신게 너무 미안했다.
시간내에 완성하는것이 중요하다. 모르는것은 빠르게 물어보자.
프로젝트를 마치고..
벌써 한달이라는 시간이 되었다.
처음에 팀배정이 되었을때 내가 가고싶었던 기업에 뽑힌점, 함께 작업하고 싶다고 생각했던 분과 팀이 된점, 학원내에서 잘하시는 분들과 팀이되서 너무 좋았다.
초기에 회사와 학원간의 날짜착오와 기획의 부족으로 일주일이라는 시간을 사용하여 실제 작업에 착수한 기간은 17일 정도였고, 간단한 작업을 주셨다고 생각했다.
그런데 막상 해보니 막힘의 연속이였다.
프로젝트가 끝나고 다음날, CTO님과의 티타임회의를 가졌는데, 여기서도 소통의 중요성을 강조하셨다.
질문을 더 많이 해야한다고 어디까지 진행되고있는지도 알려줘야한다고하셨다.
프로젝트가 끝나고 나서 서로의 생각을 말했는데 이걸 프로젝트중에 말했다면 더 좋은 과정과 결과물이 있었을거라는 생각이 들었다.
이전에도 느꼈던 소통이 중요하다고 느꼈지만, 이번 프로젝트에서 정말 뼈저리게 느꼈다.