본문 바로가기
IT

대학교 수강신청 매크로 만들기 (Python Selenium)

by 고간디 2024. 3. 10.
더보기

수능이 끝나고 목표했던 대학이 진학사 기준 8칸이어서 마음 편하게 3개월간 마음껏 놀 수 있었다

원서 접수 기간에는 6칸으로 마무리되었지만 최초합권이었고 나머지 두 곳은 교차로 상향 지원을 했다

 

안정으로 쓴 학교에 가기에는 점수가 아깝긴 하지만 목표했던 대학이고 좋은 학교 좋은 학과이기 때문에 상향 두 곳이 모두 떨어져도 상관 없어서 더 마음 편하게 놀았던 것 같다

결국 안정으로 쓴 곳으로 등록하게 되었는데 약간 아쉽기도 하지만 원하던 학과이니 만족한다

 

아무튼 대학에 등록하고 이제 수강신청 기간이 다가왔다

예전에 디시에서 신상 털고 다니며 쌓던 실력으로 에타에서 수강신청에 관한 정보들을 긁어모았다

 


우리 대학은 생각보다 견고하지 않은 시스템을 가지고 있었다

얼마 전 학교 사이트를 전체적으로 개편했는데 개편 첫날에는 초기라 그런지 이곳저곳에 보안 취약점이 가득했다

 

지금은 천천히 하나하나 고쳐지고 있는 것 같다

몇 가지 테스트해보고 싶었던 것들도 많았는데 입학도 전에 걸려서 혼날까봐 시도는 못 했다

나중에 보안 동아리에 들어가게 된다면 가능할 지는 모르지만 학교 허가를 받아 모의 침투 같은 것도 해보고 싶다

 

고등학생 때 대학생이 되면 하고 싶은 것이 수강신청 매크로 만들어보기였다

하지만 난 이제 막 입학하는 신입생이고 이번 수강신청을 잘못하면 첫 학기부터 망해버리는 것이기 때문에 조금 무서워서 매크로를 만들지도 쓰지도 않았다

어떻게 첫학기부터 신입생이 대담하게 매크로를 만들어서 사용하겠는가..

 

그래서 수강신청은 내 손으로 했다

처음 계획한 시간표와는 좀 다르게 짜졌지만 나쁘지 않게 짠 것 같다

 

각 학년별로 수강신청을 마치고 전체 수강신청 기간이 있다

나는 1학년 수강신청 기간에 수강신청을 전부 마치고 전체 수강신청 기간에 매크로를 만들었다

기간이 안 그래도 이틀 밖에 안 되는데 둘째날 오전에 만들기 시작해서 수강신청이 닫히는 오후 5시까지 6시간 안에 빠르게 만들어봤다

 

 


- 수강 시뮬레이션이라는 곳에서 과목을 미리 담아놓고 수강신청 시스템에서 신청 버튼을 클릭해 수강 신청을 할 수 있다

- 신청 버튼을 누르면 신청 완료 여부 및 오류 메세지 팝업이 나오는데 확인 버튼을 누르거나 엔터를 눌러 닫을 수 있다

- 정확히 오전 9시부터 수강신청 시스템에서 신청을 할 수 있다

- 오전 8시 30분부터 수강신청 시스템이 미리 열린다

- 수강신청 시스템에 서버 시간이 자체적으로 제공되지만 네이비즘이 더 빨랐다

 

- 이 글은 매크로를 만드는 방법을 알려주지 않는다

- 본인은 매크로를 만들어 실제 수강신청에 사용하지 않았다

- 최대 학점인 18학점을 신청하여 신청 버튼을 눌러도 최대 학점 초과 오류로 신청이 되지 않는 상태에서 테스트를 하였다

- 수강신청 기간에 매크로 제작 소식이나 매크로 프로그램을 공유한 적이 없다

- 매크로를 사용하여 수강신청을 진행할 경우 각 학교 규정에 따라 불이익을 받을 수 있으니 주의해야 한다

 

더보기

수강신청 매크로와는 상관이 없는 내용이지만 우리 학교 수강신청 시스템은 다중 로그인이 불가능하다

스마트폰, PC에서 수강신청 시스템에 동시에 로그인할 수 없다는 말이다

 


하지만 여기에는 허점이 존재한다

다중 로그인을 쿠키를 통해서 인식하는데 이 쿠키를 위조해버리면 다중 로그인이 가능해진다

 

위 사진처럼 LoginCookie의 쿠키값을 변조해주면 같은 PC의 새로운 브라우저에서도 다중 로그인이 가능하다

사실상 일반인들에게 수강신청에 도움이 되거나 효과적인 내용은 아니지만 그냥 써봤다

 

좀 더 정성 들여서 수강신청을 목숨 걸고 하겠다면 여러 컴퓨터에서 다중 로그인해서 여러 창 띄워놓고 중앙 컴퓨터에서 원격으로 매크로를 작동시킬 수도 있겠다

하지만 해보지 않았기에 여기서 발생하는 문제에 대해서는 보장 못 하겠다


난 시나리오1 과목으로 실제 수강신청을 진행했고 매크로 테스트는 시나리오3를 이용했다

앞서 말했듯 저 신청 버튼을 눌러도 난 이미 최대 학점을 신청했기 때문에 신청이 되지 않는다

 


콘솔에서 XPath를 이용해서 클릭을 해볼 수 있다

이런 식으로 작동 확인을 하면서 수강신청에 쓰이는 모든 영역의 XPath들을 복사해놨다

나중에 수강신청 기간이 끝나 사이트가 닫혀도 매크로를 개발하고 업데이트해볼 수 있도록 당장은 필요 없는 영역들도 함께 복사해뒀다

 


from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
from tabulate import tabulate
import time, os, getpass, subprocess

사용한 라이브러리이다

과목 정보를 나열할 때 tabulate를 사용했는데 원래 pandas를 사용하려고 했었다

근데 이유는 모르겠지만 모양이 자꾸 어긋나길래 tabulate로 바꿨는데 그대로라서 그냥 냅뒀다 에휴

 


def connect(): 
    global driver, url
    os.system('cls') # Linux: cls -> clear
    print("명문대학교 수강신청 시스템에 접속합니다.", end='')
    try:
        port = 1234 # Flexible
        options = Options()
        # Bot(Selenium) Detector Bypass Options
        options.add_experimental_option("debuggerAddress", "127.0.0.1:"+str(port))
        # options.add_argument("headless") # Execute in Background or not (Not Work)
        subprocess.Popen(r"C:\Program Files\Google\Chrome\Application\chrome.exe --remote-debugging-port="+str(port))
        url = "https://sugang.(univ).ac.kr/"
        driver = webdriver.Chrome(options=options)
        driver.get(url)
        driver.implicitly_wait(10)
        driver.switch_to.frame("Main")
        print("\r시스템에 성공적으로 접속했습니다.              ")
    except: # Restricted from Server Manager etc.
        print("\r알 수 없는 이유로 시스템에 접속할 수 없습니다.\n프로그램이 종료됩니다.")
        exit()

인터넷에 검색했을 때 일반적으로 나오는 사용법대로 하면 크롬 브라우저에 자동화 시스템에 의해 실행되고 있다는 문구가 나타난다

이 경우에는 학교 수강신청 사이트 관리자가 봇이 접근한 것으로 판단할 수 있다

나는 그것도 모르고 몇 시간 동안 수십번 테스트를 진행했는데 안 걸렸다

 

걸렸는데 이걸로 수강신청을 해서 과목을 잡지 않아서 봐준 것일 지도 모르겠지만 아무튼 아주 위험한 행동이었다

봇으로 수강신청을 하는 것을 걸리지 않고 싶다면 우회를 해주어야 한다

 

그 방법이 크롬 디버깅 모드로 Selenium을 실행하는 것인데 이 경우 일반 사용자가 사용하는 크롬 브라우저에서 명령 코드들이 실행된다

참고로, 이 경우에는 백그라운드 실행이 되지 않는 것 같다

headless 옵션을 추가해도 디버깅 모드가 그런지 작동이 되지 않는다

 


def login():
    print("\n시스템에 로그인을 시도합니다.", end='')
    driver.implicitly_wait(5)
    id_xpath = "/html/body/div[2]/main/div/form/input[1]"
    driver.find_element(By.XPATH, id_xpath).send_keys(user_id)
    pw_xpath = "/html/body/div[2]/main/div/form/input[2]"
    driver.find_element(By.XPATH, pw_xpath).send_keys(user_pw)
    login_xpath = "/html/body/div[2]/main/div/form/button"
    driver.find_element(By.XPATH, login_xpath).click()

이런 식으로 XPath를 통해서 영역을 찾아 클릭하고 입력하는 코드만 알면 웬만한 것은 다 할 수 있다

손으로 수강신청할 때 누르는 것들을 찾아 나열만 하면 되는 것이니..

 


내가 구현한 수강신청 매크로 프로그램의 작동 방식은 아래와 같다

  1. 대학교 수강신청 사이트 접속
  2. 대학교 포털 계정 정보를 입력받아 로그인 (디버깅 모드 사용할 경우 계정 정보 저장을 통해 생략 가능)
  3. 수강시뮬레이션 이동 후 시나리오 선택
  4. 해당 시나리오의 과목 정보 크롤링 후 신청 가능 여부와 함께 터미널에 출력
  5. 신청할 과목 번호 입력 (예를 들어 신청 가능 과목이 5개이고 그 중 2, 4번째 과목을 출력하고 싶다면 '2 4' 입력)
  6. 자동 수강 신청 (클릭 엔터 반복)

 


클릭 엔터를 반복할 때에는 신경 써야 할 것이 한 가지 더 있다

신청 버튼을 클릭한다고 해서 곧바로 팝업이 뜨는 것이 아니라 팝업 애니메이션이 들어가 있어서 약간의 시간차를 둬야 한다

실제 수강신청 시작 시간에 손으로 수강신청을 해본 결과 서버 상태에 따라서 그 시간차가 길어지기도 한다

 

때문에 확인 버튼이 생길 때까지 기다린 후 클릭을 해야 하는데 이것에는 여러 가지 이유로 implicitly_wait() 함수를 사용할 수 없었다

 


WebDriverWait(driver, 5).until(EC.presence_of_all_elements_located((By.XPATH, "/html/body/div[3]/div[2]/div/div/div/div/div/div/div/div[3]/div")))

그래서 이 함수를 사용해서 확인 버튼을 누르기로 했다

코드상에는 5초로 해놓았는데 인기 강의의 실제 수강신청 당시 로그를 보니까 6~8초 정도 딜레이가 있었어서 10초 정도로 하면 적절할 것 같다

 


더보기

사실 수강신청 매크로 프로그램이라고 하기에는 부족한 점이 너무 많다

 

- 굳이 필요없는 계정 정보 입력 받기

  어차피 디버깅 모드로 매크로 돌리니까 계정 정보는 미리 브라우저에 저장 가능

- 손 > 매크로

  사실 수강신청에서 가장 중요한 것은 클릭 엔터를 반복하는 속도보다 인기 강의를 잡는 것이다

  그러려면 가장 인기 있는 강의를 첫 번째로 두고 수강신청이 열리자마자 클릭을 해야 한다

  서버 시간에 정확히 맞춰서 클릭을 해야 하는데 매크로를 써도 서버 시간을 보며 정확히 클릭해야 하는 것은 매한가지다

- 부족한 코딩 실력

  형편없는 실력으로 만든 프로그램이다

  안 그래도 속도가 느린 파이썬으로 만든 데다가 컴퓨터에 파이썬이나 파이썬 라이브러리가 설치되어 있지 않다면 사용할 수 없다

  누군가에게 배포하거나 공유할 생각은 없지만 나만 잘 활용할 수 있는 매크로이다

 


어떻게 하면 보완할 수 있을지 생각해봤다

 

form에 과목코드만 입력하고 엔터를 눌러 수강신청을 하는 기능이 있다

form의 내용이 어느 경로로 전달되는지만 찾는다면 그 경로로 request 요청을 정각에 보내서 아주 빠르게 여러 과목들을 한꺼번에 수강신청할 수 있을 것 같다

 

여러 컴퓨터에 여러 브라우저를 쿠키 변조를 통해 열어놓고 수강신청 시도

비정상적인 수강신청 시도로 제재를 먹을 가능성이 매우 높지만 이론상 가능한 방법이긴 하다

정확히 00초에 신청 버튼을 누르기 쉽지 않으니 대충 59분 50초에서 00분 50초 사이에 일정 간격마다 각각의 브라우저에서 신청 버튼을 클릭하도록 한다면 그 중 적어도 하나의 브라우저에서는 정각에 신청 버튼을 누를 수 있지 않을까 싶다

하지만 서버 측에서는 1초 내 수많은 request를 받게 되기 때문에 오류가 발생하거나 나중에 걸릴 수도 있다

 

뭐 어찌됐건 이런 식으로 대충 수강신청 매크로를 만들어봤다

누가 따라 만들어서 악의적으로 사용할 수도 있으니 최대한 뭉퉁그려서 대충 설명해봤다

 

그래봐야 일반인들만 모르고 좀 아는 사람들은 보고 잘 따라 만들 수도 있긴 한데 언제나 행동에는 책임이 따르니 굳이 말리지는 않겠다

우리 학교 같은 경우에는 부적절한 방법으로 수강신청을 한 내역이 적발될 경우 신청한 과목들이 전부 취소가 되서 강제 반수를 하게 만든다

 

그러니 함부로 매크로를 만들어서 수강신청에 사용하지 말기를 바라며 이 글을 마친다

 

https://www.youtube.com/watch?v=H5RpmqoOEe8

 

728x90
반응형

댓글