토플 조교하다가 코딩한 썰

7 minute read

학생이었다가 조교됨

유학을 가겠다며 토플 성적을 짧은 기간 내에 만들기 위해 학원으로 향했다. 평소 논문과 여러 영어로 된 기술 블로그들을 읽으며 내용을 이해하는데 크게 불편한 점이 없었기에 자만한 마음을 가지고 토플을 시작했다가 호되게 두들겨 맞았다. 처음 공부를 시작했던 재수 때로 돌아간 듯이 아침 7시에 학원에 나가서 학원 문이 닫는 밤 10시에 나가는 게 일상이 되었다. 어디까지 꼼꼼하게 공부를 해야 하는지 가늠할 수 없었기에 철자 하나하나 꼼꼼하게 보던 나는 어느새 프로 불편러가 되었다.

선생님께서 올려주신 단어장에 있는 오타를 보고 프로 불편러가 돼버린 나는 바로 게시판에 댓글을 달았다. 다음날 학원에서 스터디를 하고 있는데 조교 선생님이 오더니 내 이름을 찾는다. 학창시절 이름 불리면 괜스레 찔리던 버릇 어디 안 갔는지 뭔가 잘못했나 라는 생각에 조용히 있었지만 4명밖에 없던 공간에서 숨는 건 불가능했다. 그런데 예상밖에 조교 선생님이 커피를 사주셨다. 알려줘서 고맙다고 한다. 사실 틀린걸 알려 드리는 게 잘못한 일은 아니었기에 이상한 일도 아니었지만 커피까지 사주는 것이 그동안 아무도 이런 작은 오타에 언급하는 일이 없었나 라는 생각도 들었다.


어타 외않되?

선생님 눈에 띈 건 그때부터인 거 같다. 그 이후로 빠진 수업자료나 오타가 있으면 사사건건 다 얘기했다. 한 달쯤 지나니 선생님이 조교 해볼 생각이 없느냐고 하신다. 평소 남 돕는 거 즐기던 나는 그때까지만 해도 자존감이 바닥에 붙어있었기에 정중히 거절 드렸으나 이후로도 계속된 요청에 결국 하기로 했고 성적이 그리 좋은 것도 아닌데 도움이 될까라는 걱정에 선생님 대답은 꼼꼼한 성격이 도움이 될 거라 생각하셨다고 한다.

프로 불편러가 느낀 가장 큰 불편

학원에는 한 명의 선생님이 정말 많은 학생을 가르친다. 특히 대규모 학원에 인기 강사라 더 많은 학생을 대상으로 질문을 받고 답변을 해야 한다. 그래서 수업 이후 쉬는 시간에 질문하지 않으면 빠르게 답변을 받는다는 것은 알 수 없는 일이다. 하루에도 선생님 메일에는 수십 통의 학생들의 메일이 쌓이고 수많은 강의와 각각의 게시판 사이에서 새로 달린 질문 글과 댓글을 찾는 건 정말 많은 시간이 소요되고 눈만 아픈 일이다. 답변이 늦을수록 학생들의 불만은 커질 수밖에 없고 선생님에 대한 아쉬움도 커지기 마련이다. 선생님께 그동안 도움도 많이 받았기에 도움이 될 수 있으면 하는 바람에 이런 수고스러움을 해결해보고자 결심했다.

프로 불편러지만 일에는 프로 게을러었기에 항상 저비용 고이득을 추구하기 위해 코딩을 해야겠다는 생각이 들었다. 평소에도 크롤링 작업은 종종 했기 때문에 대충 머리로 생각하기에는 크게 어려운 작업은 아니라고 생각했다.

작업 시작

한 가지 걱정할 점은 과연 만들어도 쓸모 있을까였다. 선생님마다 게시판에 공지를 많이 올리기도 하고 아니기도 하다. 내가 조교로 일하는 선생님은 전자였다. 수십개의 반별 게시판에서 수많은 공지글과 학생들의 게시글을 찾아 댓글이 있는지 매일 수시로 확인하는 것고 일이였지만 과연 댓글이 많이 달릴까도 문제였다. 굳이 한 달에 몇 개 안 달리는 댓글 때문에 내 아까운 시간을 소비할 이유는 없었다. 그래서 한 달간 얼마나 댓글이 달릴까 한 달 정도 있어 봤다. 168개였다. 만들기로 했다.

우선 굳이 내가 만들어야 하나 라는 생각이 들었다.

학원에 IT 부서가 있었기에 생각하기에는 그쪽에서 처리하는 게 더 효율적으로 빠르지 않을까 싶었다. 그러나 선생님도 이미 여러 번 요청을 했었고 돌아오는 답변은 ‘시간이 오래 걸릴 거다’였다. 그도 그럴 것이 모든 선생님이 필요한 것도 아니었기에 그렇게 시간을 들여 개발할 것도 아니었다.

처음에 계산해본 건 내가 하루에 댓글 찾는데 들어가는 시간대비 개발 시간 + 개발한 후 댓글 찾는 시간이었다. 선생님이 수업하는 강의는 상상 이상으로 많았다. 문제는 수업 이름이 다 비슷하게 생기고 같은 시간대, 같은 수업이어도 10회와 20회로 나뉘는 경우가 있어서 꼼꼼히 보지않으면 지나치기 십상이었다. 일주일 정도 그렇게 일일이 찾다 보니 30분은 훌쩍 지나갔다. 일하는 기간 두 달에 주 3일 근무로 계산하면 대략 총 720분(12시간)이다. 그렇다면 개발하는데 대충 5시간 + 하루 5분으로 줄이면 총 7시간이니 5시간은 벌은 셈이다. 거기에 이후로도 선생님과 조교들이 사용하게 되면 더 많은 시간을 절약하는 것이니 더더욱 개이득이지 않나 싶다.

처음에 생각하기에는 댓글이 새로 생길 때마다 선생님께 알람이 가도록 하는게 좋겠다 생각했다. ‘처음에 생각하기에’라는 얘기를 했다는 건 생각대로 흘러가지 않았다는 걸 말한다. 선생님은 항상 바쁘기 때문에 굳이 바로 알람을 받을 필요가 없었고 오히려 미리 알람을 받으면 잊혀질 가능성이 높았다. 그래서 언제들 확인할 수 있는 댓글만 모아놓은 페이지를 만들기로 했다. ‘그러나(However)’, 여기도 여전히 문제가 있다.

학생들이 질문하는 방법은 크게 두 가지이다. 첫 번째는 선생님이 올린 게시글에 답변을 다는 경우이고 두 번째는 학생이 게시글을 작성하는 경우이다. 반대로(In other words), 선생님이 학생들에게 답변을 주는 경우도 두 가지로 생각해볼 수 있다. 그렇다면 선생님이 올린 게시글은 학생이 댓글을 달고 선생님이 대댓글로 답변을 했는지 안 했는지만 확인하고 학생이 게시글을 다는 경우는 선생님이 답변 댓글을 했는지 안 했는지만 검사하면 되겠지만 그렇게 쉽게 흘러갔다면 주구 절절 이렇게 글이 길어지지도 않았을 거고 개발시간도 5시간으로 안 잡았을 것이다. 그래서 내가 내린 결론은 댓글이 달린 게시글 주소와 댓글 수만 파악해서 정리하는 것이었다.

대충 가져올 특성들은 아래로 정리했다.

Features Description
title 게시글 제목
name 작성자 이름
category 1. teacher 2. student
class_name 강의명
date 작성시간
nb_comment 댓글 수
url 게시글 url

강의 게시판은 대략 이렇게 생겼다. 중간은 따로 비공개 내용이기에 지저분하게 지워놨다. 사진에는 10개밖에 없는 거처럼 보이지만 아래 더 있다. 선생님을 보며 세상에 공짜는 없다는 걸 새삼 다시 느낀다. 사진을 보다시피 각 강의는 강의 별 반별 게시판이 있고 그 안에 과목별 게시글이 있다. 강의 게시판에서 반별 게시판을 하나씩 들어갔다 돌아왔다 반복할 필요없이 한 번에 각 반별게시판 주소를 모두 가져온 후 각 반별 게시판을 하나씩 들어가서 댓글이 있는 게시글만 하나씩 쏙쏙 따오면 끝이다.

  1. 강의별 게시판 주소 가져오기
  2. 각 게시판별 댓글 검사

Notion is Everywhere

수집한 데이터를 어디에 업데이트하면 좋을까 하다가 내린 결론은 역시 노션이다. 선생님과 일하며 그동안 엑셀로 업무일지를 주고받았다고 하셔서 노션을 써도 되냐고 여쭤봤고 이전부터 내가 노션을 써온 걸 선생님도 알았고 계셨고 노션이 좋아보인다는 말을 하셔왔기에 조교 일도 모두 노션에 정리하기로 했다. 데이터를 입력하는 건 예전에 봤던 notion api를 쓰면 됐기에 문제 될 건 없었다. 또한 기존에 누적된 테이블 정보를 불러올 때는 얼마전 개발했던 notionist를 사용하면 되었다.

Screen Shot 2020-08-01 at 1 44 03 AM

파이썬으로 노션을 사용하기 위해서는 token_v2와 url이 필요하다. 방법은 이전에 간단히 만들었던 notionist 글에서 확인할 수 있다.

Github Action

다음은 계속 댓글을 업데이트하기 위해서는 코드를 주기적으로 실행할 필요가 있었다. 이전에 크롤링을 사용할 때는 주기적으로 계속 긁어올 일이 없어서 따로 고민해 본 적은 없었지만 이번에 고민할 일이 생겼다. 그러나 마침 올해 초 github action에 관한 얘기가 시끌시끌했던 기억이 있어서 고민은 그렇게 오래가지 않았다. 이번에 사용할 기회가 생겨서 잠깐 알아봤는데 어렵지 않게 만들 수 있었다. 글또장이신 변성윤님 글 도움을 많이 받았다. 존경존경

이제 전부 계획은 다 했으니 코딩만하면 될 터였다.

코드를 뜯어보자

코드 구조는 크게 복잡한거 없다. comments.py에는 크롤링에 필요한 함수들을 만들어놨고 main.py에서 호출해서 사용했다. python.app.yml이 github action에 필요한 설정들이 있다. 모든 내용은 Hackers Assistance github에서 확인할 수 있다.

Hackers Assistance
│  .gitignore
│  comments.py
│  main.py
│  README.md
│  requirements.txt
│
└─.github
   └─workflows
           python-app.yml

requirements.txt

코드를 실행하기 위한 모듈들에 대한 정보를 제공해주어야 github action을 사용할 때 필요한 모듈을 설치할 수 있다. 코드를 작성하며 사용된 모듈은 크게 3가지 이다. pandas는 없어도 될 줄 알았는데 없으니까 모듈이 없다고 에러가 생긴다. 크롤링은 selenium과 beautifulsoup4를 사용했고 노션에 데이터를 입력하는일은 notion과 notionist를 사용했다. notionist는 이전에 기존 notion api는 collection을 불러와서 dataframe 형태로 불러오는데 불편함을 느껴 만든 모듈이다.

selenium==3.141.0
notion==0.0.25
notionist==0.2
pandas==1.0.3
beautifulsoup4==4.7.1

comments.py

크게 6개 함수로 나누어져있다.

  1. get_board_list
    • 로그인 후 강의게시판으로 들어가 리스트를 가져온다
  2. get_board_urls
    • 강의게시판 리스트에서 각 반별게시판 주소를 가져온다
  3. get_is_comments
    • 반별게시판에 들어가 댓글이 있는지 여부를 판단한다
  4. get_comments_url
    • 댓글이 있다면 필요한 속성들을 긁어온다
  5. add_notion
    • 가져온 데이터를 노션 페이지에 테이블로 생성한다
  6. get_schema_comments
    • 노션 테이블 속성을 정의한다
  7. update_comments_table
    • 기존에 작성된 테이블과 비교하여 업데이트 한다.

main.py

위에서 작성한 함수들을 호출해서 하나씩 딱딱 써주면 끝이다. os.environ을 사용한 이유는 코드 실행을 위해 필요한 입력값이 노출되면 안되기 때문에 github settings에서 secrets을 통해 key와 value를 입력하면 노출되지않고 몰래 입력값을 사용할 수 있다.

import os 
from comments import *

if __name__=='__main__':

    ha_id = os.environ['HA_ID']
    ha_pwd = os.environ['HA_PWD']
    token_v2 = os.environ['TOKEN_V2']
    ha_notion = os.environ['HA_NOTION']

    driver = get_board_list(ha_id, ha_pwd)
    boards_info, driver = get_board_urls(driver)
    total_df = get_comment_urls(driver, boards_info)
    print('[COMPLETE] Number of boards with comments: ',total_df.shape[0])

    add_notion(token_v2, ha_notion, total_df)
    print('[COMPLETE] Create a table in Notion')

python-app.yml

github action을 사용하기 위해서는 이와 같이 세팅값이 필요하다. Workflows에 대한 구조는 위에 변성윤님의 글을 다시 참고하면 된다.

OS는 unbuntu, 코드는 python 3.7에서 실행했고 실행주기는 1시간 단위로 실행하게 설정했다. 맨 처음에는 cron을 어떻게 설정하는지 몰랐지만 Github Docs에서 확인할 수 있다.

사실 이것만 알면 금방 이해가 될 수도 있다.

┌───────────── minute (0 - 59)
│ ┌───────────── hour (0 - 23)
│ │ ┌───────────── day of the month (1 - 31)
│ │ │ ┌───────────── month (1 - 12 or JAN-DEC)
│ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT)
│ │ │ │ │                                   
│ │ │ │ │
│ │ │ │ │
* * * * *

처음엔 github action으로 selenium을 쓸 수 있을까 생각했는데 가능했다. 단, pip install을 위한 설정값처럼 우분투 환경을 세팅해주어야한다. 아래 Install ubuntu packages처럼 chrome과 chromedriver를 설치해주면 문제없이 사용이 가능하다.

name: Hackers Comments Crawler

on:
  schedule: 
    - cron: '0 * * * *'

jobs:
  build:

    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [3.7]

    steps:
    - uses: actions/checkout@v2
    - name: Set up Python $
      uses: actions/setup-python@v2
      with:
        python-version: $
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
    - name: Install ubuntu packages
      run: |
        sudo apt-get install google-chrome-stable 
        wget https://chromedriver.storage.googleapis.com/2.40/chromedriver_linux64.zip
        unzip ./chromedriver_linux64.zip
    - name: Run main.py
      run: |
        python main.py
      env:
        HA_ID: $
        HA_PWD: $
        TOKEN_V2: $
        HA_NOTION: $

맺음말

다음 달은 시간 절약하면서 다른 일을 더 많이 할 수 있을 거 같다. 부디 이걸 만드는데 들어간 시간이 아깝지 않기를 바랄 뿐이다. 현재 내 머리가 부족해서 이 이상의 효율적인 방법은 생각은 안 나지만 선생님들이나 다른 조교들이 유용하게 사용하길 바라며 개선할 사항이 있으면 조금씩 고쳐볼 생각도 있다.

시간이 참 빠르다. 글또를 하면서 최소 이주에 한 번은 글을 써야지 생각했는데 예치금 아까운 줄 모르고 야금야금 까먹고 있다. 그래도 이번 기회에 오랜만에 작은 프로젝트 하나 해보면서 끄적일게 생겼다. 그동안 여러 많은 일이 있었지만 아직은 기록하기엔 불확실한 일들이 많아서 글 쓰는 빈도가 줄었다. 아마 한 달 뒤면 쓸 글이 참 많지 않을까 싶다.

그보다 기술 문서나 전공 관련된 공부를 더 해야 하는데 시험기간에 시험공부 빼고 다 재밌는 거처럼 전공 공부 말고 다 재밌다. 역시 글은 다른 기술문서를 번역하고 공부하는 글보다 개인적인 경험에서 우러나오는 글을 쓰는게 더 재밌는거같다.

Categories:

Updated:

Leave a comment