코딩스토리

크롤링 연습 - 백준 채점 현황으로 출석 체크 하기 본문

Web/JavaScript

크롤링 연습 - 백준 채점 현황으로 출석 체크 하기

kimtaehyun98 2021. 3. 4. 16:37

산학 프로젝트 관련 준비로 크롤링을 공부하려고 구글링을 해봤다.

 

일단 Youtube에는 대부분 파이썬으로 크롤링을 하는데 우리는 JavaScript를 사용할 예정이므로 더 찾아보니

 

크롤링을 하려면 Ajax, Axios, Cheerio... 등등 공부할게 너무 많았다.

 

지금 공부한 게 0, 말 그대로 바닥이어서 일단은 가장 많이 들어보고 언젠간 반드시 해야 할 것 같았던 Ajax를 공부하기 시작했다.

 

생코 강의를 열심히 듣다가 밥 먹고 잠깐 침대에 누워서 Yotube를 켰는데 무슨 알고리즘인지 추천 영상에 Open Api를 활용하는 영상이 있었다.

 

그 영상을 보니 Javascript, JQuery, Ajax를 사용하여 Api를 사용하는 방법을 대충? 알게 되었다.

 

갑자기 소학뽕에 취해 Api를 가져와서 코딩해볼까 하고 앉았는데.. 지금 그게 중요한 게 아니었다..

 

어쨌든 지금은 크롤링을 어떻게 하는지 감을 찾는 게 중요하므로 간단한 주제로 시도해보려고 한다.

 

주제 : 백준 채점 현황 기록을 가져와서 해당 문제를 풀었는지 안 풀었는지 확인하기

 

일단 백준의 채점 현황에 들어가서 어떤 식으로 html이 이루어져 있는지 확인해봤다.

 

 

잘 보면 정말 다행히도 해당 페이지에는 tbody 태그가 하나밖에 없고, 이 tbody 태그 안에 내가 원하는 정보들이 들어있었다.

 

일단은 가장 중요한 건 이 html을 받아오는 거여서 그것부터 해보자 생각하고 해 봤는데... 왜 안됨?

 

에이.. 설마..???

 

(이 간격이 3시간임)

 

와... 3시간 만에 해결함

const axios = require('axios');
const cheerio = require('cheerio');
const url = 'https://www.acmicpc.net/status?user_id=kimtaehyun98';

axios.get(url)
  .then(adata => {console.log(adata);})
  .catch(err => {console.log(err);});

이 코드를 cmd에서 실행시키는데 계속 안됨.

 

구글링 2시간 + 혼자 속으로 욕하기 1시간 후

 

stack overflow에서 node-modules 삭제해보란 글을 보고 삭제 후

 

node index.js로 실행시켜 보니 

 

axios 모듈이 없다고 나와서 다시 npm install axios 한 후 실행시켜보니

 

후.. 겨우 겨우 어찌 저지 가져오긴 했다.

 

이제부터 시작인듯하다.... (진짜 울고 싶다.. 이 길은 내 길이 아닌 거 같아..)

 

이제부터는 구글링 스킬이 중요하다.

 

일단 내가 원하는 정보는 문제 번호와 맞았는지 틀렸는지이다.

 

문제 번호부터 가져와보자. (코드는 아래에 첨부할게요)

 

 

앞의 '/problem/'은 필요 없기 때문에 substr로 제거해줬다.

 

이제 다음으로 맞았는지 틀렸는지를 확인해야 한다.

 

처음에 html을 분석하다가 착각한 부분이 있었다.

 

내가 원한 건 정확히 "맞았습니다!!"라는 text인데 이게 이상하게 불러와지지가 않았다.

(아직도 잘 모르겠음..ㅠ)

 

그래서 혹시나 해서 다시 html을 째려보고 있었는데 뭔가 해결책이 보였다.

 

잘 보면 "맞았습니다!!"를 받은 문제의 클래스 이름은 "result-ac"로 되어있고 틀렸으면 "result-wa"로 되어있었다.

 

이 방법으로 하면 오히려 더 좋다.

 

처음 방법대로 "맞았습니다!!"를 불러오면 "100점" 같이 서브 태스크가 있는 문제들을 판별해낼 수가 없었다.

 

오히려 좋아!!

 

일단 가져왔으니 이쁘게 바꿔보자. 

 

어차피 필요한 건 "ac" 또는 "wa" 이므로 이번에도 substr을 사용했다.

 

후.. 거의 다 됐다.

 

이제부터는 단순 알고리즘이다.

 

내가 생각한 알고리즘은 다음과 같다.

 

  1. 미리 문제 번호 지정 (3문제)
  2. 각 문제 번호마다 지정된 문제 번호와 일치하는지 확인한다.
  3. 일치한다면 'ac' 인지 'wa'인지 확인한다. 

굉장히 단순하면서 간단한 알고리즘이다.

(설명하기에는 너무 귀찮고 더러워서.. 코드로 남길게요)

 

이렇게 해서 실행시켜보면!!

 

정상적으로 출력이 된다!

 

전체 코드는 다음과 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
const axios = require('axios');
const cheerio = require('cheerio');
const url = 'https://www.acmicpc.net/status?user_id=kimtaehyun98';
 
let problem_num = [];
let YesorYes = [];
 
axios.get(url)
  .then(all_data => {
    // 성공적으로 data(html)를 받아왔다면
    console.log("Success!!");
 
    // cheerio 모듈을 사용하여 data를 저장하고
    var $ = cheerio.load(all_data.data);
 
    // 해당 html중 <tbody> 태그의 <tr> 태그의 3번째 <td> 태그의 <a> 태그의 href 를 가져오면 된다.
    $('tbody>tr>td:nth-child(3)>a').each((index, item) => { // 여기서 each는 반복문이라 생각하면 됨!
      problem_num.push(item.attribs.href.substr(9)) // 문제 번호를 저장하기
    });
 
    // 해당 html중 <tbody> 태그의 <tr> 태그의 4번째 <td> 태그의 <span> 태그의 <span>의 클래스 이름을 가져오면 된다. 
    $('tbody>tr>td:nth-child(4)>span>span').each((index, item) => { // 여기서 each는 반복문이라 생각하면 됨!
      var name = item.attribs.class;
      YesorYes.push(name.substr(7,2));
    });
 
    let today_problem = ['11559''1477''9370'];
    let doit = [falsefalsefalse];
 
    for(let i = 0; i < problem_num.length; i++){
      let numb_index = today_problem.indexOf(problem_num[i]); // 제출한 문제가 오늘 풀어야 하는 문제에 해당하는지 확인
      if(numb_index != -1) { // 오늘 풀어야 했던 문제라면
        if(YesorYes[i] === 'ac'){ // ac를 받았다면
          doit[numb_index] = true// true로 변경 = 풀었다!
        }
      }
    }
 
    // 출력을 위해 푼 문제 번호 저장한 배열 생성
    var print_arr = [];
    for(let i = 0; i < 3; i++){
      if(doit[i] === true) print_arr.push(today_problem[i]); // true라면 푼 문제로 추가
    }
 
    var check = '결석';
    if(today_problem.length === print_arr.length) check = '출석';
 
    // 몇 문제 풀었는지, 다 풀었는지 안풀었는지, 말 그대로 출석부 출력
    console.log(
      `********************************************************
      id : kimtaehyun98
      오늘 풀어야 하는 문제 번호 : ${today_problem}
      푼 문제 번호 : ${print_arr}
      출석 : ${check}
********************************************************`
    )
})
  .catch(err => {console.log(err);});
cs

어찌 저찌 크롤링에 입문하긴 했지만 아직은.. 많이 어렵다 ㅎ

 

 

이번 크롤링의 한계점

 

1. 원하는 id를 미리 저장해야 함 (url을 미리 저장해놓았음) 

-> 이건 바꾸는 건 어렵지 않을 것 같다. 사용자에게 입력받고 그걸 url로 만들어서 주면 될 듯?

 

2. 문제 번호 고정 (미리 저장해 놓음)

-> 이것의 해결방법도 1번과 비슷할 듯

 

3. 서브 태스크 있는 문제 판별 불가

-> 해결!

 

4. web을 화면으로 어떻게 띄워야 하는지 모르겠음

-> 공부 예정

'Web > JavaScript' 카테고리의 다른 글

HTTP 프로토콜  (1) 2021.04.11
ES6 공부  (0) 2021.02.25
5. 실행 컨텍스트와 클로저  (0) 2021.01.19
4. 함수와 프로토타입 체이닝 - 2  (0) 2021.01.15
4. 함수와 프로토타입 체이닝 - 1  (3) 2021.01.11
Comments