방명록
- [개인] 워크넷 맞춤 구직 정보 이메일로 받기 #2 | dotenv, nodemailer를 추가해 크롤링 정보를 개인 이메일로 발송2022년 04월 15일 16시 24분 53초에 업로드 된 글입니다.작성자: DandyNow728x90반응형
| 개발 동기
매번 워크넷에 들어가 비슷한 검색어를 입력하는 것이 번거로웠다. 스케줄링까지 적용해 매일 정해진 시간에 자동으로 이메일 구직 정보를 받아보는 프로그램을 만들고자 한다.
| 개발 목표
- 워크넷 정보를 크롤링한다.
- 크롤링된 정보를 개인 메일로 발송한다.
- 크롤링된 정보를 매일 지정한 시간에 개인 메일로 발송한다.
- 이상의 기능에 GUI를 적용한다.
| 사용 기술
이번에 사용한 모듈은 dotenv, nodemailer이다.
dotenv는 깃허브에 이 프로젝트를 커밋, 푸시하더라도 구글로부터 받은 메일 키는 제외되도록 하기 위해 사용하였다.
nodemailer는 크롤링된 정보를 개인 이메일로 발송하기 위해 사용하였다.
※ node.js에서 진행한 이번 프로젝트에서 현재까지 사용한 모듈은 axios, cheerio, dotenv, nodemailer이다.
| 진행 현황
개발 목표 중 1, 2를 달성하였다.
#1에서 진행했던 크롤링 정보에 "경력, 학력, 위치"를 추가했다.
| 다음 단계
cron 식을 적용해 매일 정해진 시간에 크롤링하여 메일을 발송하도록 할 것이다.
| 문제 해결
- cheerio의 find함수를 사용할 때 원하는 정보를 타깃 하기 위한 css 선택자를 지정하는 것이 어려웠다. eq()를 사용해 적절히 해결했다.
- 크롤링된 문자열에 원하지 않는 문자나 문자열을 replace함수를 사용해 제거하고자 하였다. 이때 정규식이 지식이 짧음을 깊이 실감했다! 원하지 않는 문자열이 "학력"에서 발생했는데 모든 경우에 동일한 문자열이라 정규식을 사용하지 않고 해결했다.
| 작성 코드
const axios = require("axios"); const cheerio = require("cheerio"); require("dotenv").config({ path: `nodemailer/.env` }); const nodemailer = require("./nodemailer"); // 크롤링 대상 const getHTML = async (keyword, resultCnt, regionNumber) => { try { const html = // getJobs()을 호출할 때 워크넷 url은 "검색어(encodeURI), 검색 결과 수(resultCnt), 지역코드(regionNumber)"를 동적으로 받음 ( await axios.get( `https://www.work.go.kr/empInfo/empInfoSrch/list/dtlEmpSrchList.do?careerTo=&keywordJobCd=&occupation=&templateInfo=&shsyWorkSecd=&rot2WorkYn=&payGbn=&resultCnt=${resultCnt}&keywordJobCont=&cert=&cloDateStdt=&moreCon=&minPay=&codeDepth2Info=11000&isChkLocCall=&sortFieldInfo=DATE&major=&resrDutyExcYn=&eodwYn=&sortField=DATE&staArea=&sortOrderBy=DESC&keyword=${encodeURI( keyword )}&termSearchGbn=all&carrEssYns=&benefitSrchAndOr=O&disableEmpHopeGbn=&webIsOut=&actServExcYn=&maxPay=&keywordStaAreaNm=&emailApplyYn=&listCookieInfo=DTL&pageCode=&codeDepth1Info=11000&keywordEtcYn=&publDutyExcYn=&keywordJobCdSeqNo=&exJobsCd=&templateDepthNmInfo=&computerPreferential=®DateStdt=&employGbn=&empTpGbcd=®ion=${regionNumber}&infaYn=&resultCntInfo=${resultCnt}&siteClcd=all&cloDateEndt=&sortOrderByInfo=DESC&currntPageNo=1&indArea=&careerTypes=&searchOn=Y&tlmgYn=&subEmpHopeYn=&academicGbn=&templateDepthNoInfo=&foriegn=&mealOfferClcd=&station=&moerButtonYn=&holidayGbn=&enterPriseGbn=all&academicGbnoEdu=noEdu&cloTermSearchGbn=all&keywordWantedTitle=&stationNm=&benefitGbn=&keywordFlag=&essCertChk=&isEmptyHeader=&depth2SelCode=&_csrf=afefc5c3-fc99-440b-9f6d-563efe24d151&keywordBusiNm=&preferentialGbn=&rot3WorkYn=&pfMatterPreferential=®DateEndt=&staAreaLineInfo1=11000&staAreaLineInfo2=1&pageIndex=1&termContractMmcnt=&careerFrom=&laborHrShortYn=#viewSPL` ) ).data; return html; } catch (e) { console.log(e); } }; // 크롤링, 파싱 처리 const parsing = async (page) => { const $ = cheerio.load(page); const jobs = []; const $jobList = $("tbody tr"); $jobList.each((idx, node) => { const jobTitle = $(node).find(".cp-info-in:eq(0)").text().trim(); // 채용공고명 const url = "https://www.work.go.kr" + $(node).find(".cp-info-in > a").attr("href"); // 채용공고 상세 보기 url const company = $(node).find(".cp_name:eq(0)").text().trim(); // 회사명 const experience = $(node).find("em:eq(0)").text().trim(); // 경력 const education = $(node) .find("em:eq(1)") .text() .trim() .replace("\n\t\t\t\t\t\t\t\t\t\t", ""); // 학력 const location = $(node).find("em:eq(2)").text().trim(); // 회사 위치 if (jobTitle != "") { jobs.push({ jobTitle, url, company, experience, education, location, }); } }); console.log(jobs.length); // 총 검색된 게시글 수를 콘솔창에서 확인 return jobs; }; // 검색어(keyword), 검색 결과 수(resultCnt, 최대 검색 건수 기본값 10), 지역코드(regionNumber) const getJobs = async (keyword, resultCnt = "10", regionNumber = "") => { const html = await getHTML(keyword, resultCnt, regionNumber); const jobs = await parsing(html); console.log(jobs); // 이메일 테이블 생성 및 발송 const h = []; h.push('<table style="border:1px solid black;">'); h.push("<thead>"); h.push("<tr>"); h.push("<th>구인제목</th>"); h.push("<th>회사명</th>"); h.push("<th>경력</th>"); h.push("<th>학력</th>"); h.push("<th>위치</th>"); h.push("</tr>"); h.push("</thead>"); h.push("<tbody>"); jobs.forEach((j) => { h.push(`<tr>`); h.push(`<td><a href="${j.url}">${j.jobTitle}</a></td>`); h.push(`<td>${j.company}</td>`); h.push(`<td>${j.experience}</td>`); h.push(`<td>${j.education}</td>`); h.push(`<td>${j.location}</td>`); h.push(`</tr>`); }); h.push("</tbody>"); h.push("</table>"); const message = { from: "ubithus@gmail.com", to: "ubithus@gmail.com", subject: `${keyword} 구인 회사 정보`, html: h.join(""), }; await nodemailer.send(message); }; getJobs("javascript", 1000, 26000); // 검색어 , 최대 검색 결과 수, 지역(26000 - 부산전체)
// nodemailer/index.js const nodemailer = require("nodemailer"); const config = { service: "gmail", host: "smtp.gmail.com", port: 587, secure: false, auth: { // dotenv 사용 user: process.env.GOOGLE_MAIL, pass: process.env.GOOGLE_PASSWORD, }, }; const send = async (data) => { const transporter = nodemailer.createTransport(config); transporter.sendMail(data, (err, info) => { if (err) { console.log(err); } else { return info.response; } }); }; module.exports = { send, };
728x90반응형'프로젝트 > [개인] Web Crawling E-Mail Service' 카테고리의 다른 글
[개인] 워크넷 맞춤 구직 정보 이메일로 받기 #3 | 정규식 적용 (0) 2022.04.20 [개인] 워크넷 맞춤 구직 정보 이메일로 받기 #1 | axios, cheerio 이용한 웹 크롤링 (0) 2022.04.14 다음글이 없습니다.이전글이 없습니다.댓글