ETOOS, 왜 일을 이렇게 하는거야

재현·2021년 5월 15일
0

ETOOS

목록 보기
1/6
post-thumbnail

Puppeteer 를 다룬 글 입니다.

STORY

주 5일 오전7시30분 ~ 오후 4시30분
이투스247 어딘가에서 일을 하고 있다.

데일리 테스트 라는 시스템이 있는데
월~금 국어 / 수학
월,수,금 영어 시험을 치룬다.

학원생은 대략 90명 정도 되는데
그 중에서 한 절반 정도? 시험을 치룬다.
일주일에 생성되는 데이터 개수는 대략
600개 정도 생긴다.
한달로 치면 대략 2400개 정도.

원장님께서 이제 데일리 테스트 치룬 결과를 종합해
꾸준히 참여한 학생들에게 시상을 하겠다는...
엑셀에 이름 하나하나 넣고 그날 바로 시험 치룬 학생들을
한 명, 한 명 다 일일이 O 치자는.. 1시간 안 걸릴 거라는...
말을 듣고 일단 엑셀에 함수 몇 개를 넣고 만든 다음에
"이전에 일일이 수기로 작성하는 것도 좋지만,
이렇게 하면 시간이 훨씬 더 절약이 돼서 이렇게 해도
좋을 것 같습니다." 라고 설득해서 이 방법을 사용하기로 했다!
하지만 엑셀로 하기에도 내가 10개씩 나열되어 있는
페이지를 하나하나 복사 -> 붙여넣기 해야하는 수고스러움.

멍청해지기 싫기에 배우고 있는 Javascript 를 이용해
앓고 있는 문제를 해결해 보려 한다!

크롤링을 해야해서 여러 글을 찾아보다
1. Javascript 로 써야하며
2. 브라우저 제어 기능이 다양한
Puppeteer 를 써보기로 했다.

CODE

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        headless : false,
        defaultViewport :  null }
        
    );
    const page = await browser.newPage();
    await page.setViewport({width: 1920, height : 800});
    await page.goto('열고자하는 Page');  
    
    await page.type('#mem_id', '개인ID');
    await page.type('#pwdtmp', '개인PW');
    await page.click('.btn_login');
    await page.waitForNavigation;
    
    await page.waitForSelector('#lnbmenu > ul > li:nth-child(2) > a');
    await page.click('#lnbmenu > ul > li:nth-child(2) > a',{delay: 100});
    await page.waitForSelector('#m_PB200717 > a');
    await page.click('#m_PB200717 > a',{delay: 100});
    await page.waitForNavigation;
    
    await page.waitForSelector('#records_form > div > img:nth-child(3)');
    await page.click('#records_form > div > img:nth-child(3)', {dealy : 100});
    await page.waitForSelector('#ui-datepicker-div > table > tbody > tr:nth-child(1) > td:nth-child(7) > a');
    await page.click('#ui-datepicker-div > table > tbody > tr:nth-child(1) > td:nth-child(7) > a', {dealy : 100});
    await page.waitForSelector('#btn_search');
    await page.click('#btn_search', {dealy : 100});

    await page.waitForSelector('#container > div.contents > div.wrap_tbl_sdw.mgt_30');

    const data = await page.evaluate(()=> {
        const tds = Array.from(document.querySelectorAll('#container > div.contents > div.wrap_tbl_sdw.mgt_30'))
        return tds.map(td => td.innerText)
    });
    console.log(data);
    
})();

목적

구글에 puppeteer 를 치면 무수히 나오는 좋은 참고 자료들이 많기에
코드를 작성하면서 헷갈렸던 부분이나 오류를 해결한 부분에 대해 작성해보고자 한다.

0. 목차

  1. Login
  2. My Page
  3. Daily Test Page
  4. Click Datepicker
    • 1일부터 searching 할 수 있게
  5. Data 추출

1. 왜 ID, PW 가 작성이 안되지?

	await page.type('#mem_id', '개인ID');
	await page.type('#pwdtmp', '개인PW');
	await page.click('.btn_login');

.type Method는 각 selector 에 맞는 정보를 입력해준다.
나는 처음에 tag 를 못 찾아서 헤매다
크롬의 검사 - Select an element 를 이용해 각각의 tag 를 찾은 뒤
ID, PW 를 입력시켜주었다.
이후 로그인 버튼 클릭을 위하여
class= btn_login 를 .click Method 에 입력시켜주었다.

(ID, PW 가 노출되는 것을 방지하고자, 현재 환경변수를 공부하고있다!)

2. 왜 다음 페이지로 안넘어가지?

          await page.waitForSelector('#lnbmenu > ul > li:nth-child(2) > a');
          await page.click('#lnbmenu > ul > li:nth-child(2) > a',{delay: 100});
          await page.waitForSelector('#m_PB200717 > a');
          await page.click('#m_PB200717 > a',{delay: 100});
          await page.waitForNavigation;

My Page -> Daily Test Page
넘어가는 과정 중 다음 페이지로 넘어가지 않는 오류에 마주했다.
구글링 열심히 해서 Selector 를 searching 하기 전에 click 하라는 명령에
오류가 났던 것이다.
그래서 .waitForSelector Method와 dealy:100 를 추가해 오류를 해결했다.
이후 .waitForNavigation 을 이용해 페이지가 안정적으로 로딩됨을 요했다.

3. Data 추출

            const data = await page.evaluate(()=> {
                const tds = Array.from(document.querySelectorAll('#container > div.contents > div.wrap_tbl_sdw.mgt_30'))
                return tds.map(td => td.innerText)
            });
            console.log(data);

페이지를 crawling 한 다음 Data 를 parsing 하기 위해
우선 Daily Test page 에 나와있는 table 자체를 추출했다.

(아직 .evaluate 개념 이해가 잘 가지 않아 정리 후 수정 예정!)

4. 수정 예정

  1. 추출한 Data 를 Google Sheet 로 전송
  2. 반복 과정을 반복문과 배열을 이용해 더욱 깔끔하게 수정
  3. 월 별 달력의 1일의 날짜(위치)가 다르기 때문에 매달
    코드를 수정하지 않는 방법을 찾아야함

결과

  • 참고
  1. Puppeteer Main Page
    https://github.com/puppeteer/puppeteer/blob/main/docs/api.md

  2. 환경변수를 이용한 ID, PW 숨기기
    https://seohyun0120.tistory.com/entry/severless-%ED%95%99%EA%B5%90-%EA%B3%B5%EC%A7%80%EC%82%AC%ED%95%AD-%ED%81%AC%EB%A1%A4%EB%9F%AC-Puppeteer-AWS-Lambda-DynamoDB-slack

profile
Do Work As We & Respect 🙆🏾 🙆🏻‍♂️ 🙆🏻‍♀️ 🙆‍♀️

0개의 댓글