개발로그

안전교육 매크로 만들기(2021.12.02)

한상규 2021. 12. 2. 13:39

https://github.com/HanSangKkyu/safety_edu

 

GitHub - HanSangKkyu/safety_edu: 건국대학교 안전교육 매크로

건국대학교 안전교육 매크로. Contribute to HanSangKkyu/safety_edu development by creating an account on GitHub.

github.com

시작하기 앞서

연구실 안전교육 ... 매학기 전국의 많은 대학생들을 괴롭힌다. 법정의무교육이라 무조건 들어야 한다.

안전교육 스킵방법이라고 구글링해서 쉽게 들었던 기억이 있어서 이번에도 해봤는데 모두 막혔다. 일 열심히 하네?

개발자 도구 열어서 콘솔에 js 스크립트 입력하는 방법이 모두 안돼서 직접 만들기로 했다.

 

스킵이 아닌 매크로

이제까지 방법들은 강제로 다음 페이지로 넘어가게 하는 js 스크립트를 썼다.

아주 빨라서 좋았는데 이제는 비정상적인 방법이라고 경고 메시지가 나온다. 

결국 selenium과 webdriver를 이용해서 자동으로 다음 버튼을 눌러주는 매크로를 만들기로 결정했다.

 

크롬 버전 알아내기

 

 

버전에 맞는 크롬 드라이버 다운로드

https://chromedriver.chromium.org/downloads

 

ChromeDriver - WebDriver for Chrome - Downloads

Current Releases If you are using Chrome version 97, please download ChromeDriver 97.0.4692.20 If you are using Chrome version 96, please download ChromeDriver 96.0.4664.45 If you are using Chrome version 95, please download ChromeDriver 95.0.4638.69 For o

chromedriver.chromium.org

위 URL로 들어가면 크롬 드라이버를 다운받을 수 있다.

 

자신의 크롬 버전에 맞게 다운로드 한다. 나는 96버전이었다.

 

자신의 운영체제에 맞게 다운로드 한다. 대부분 win32 아니면 mac64일 것이다. 나는 mac64_m1이다.

 

selenium으로 매크로 만들기

selenium을 사용하였다.

selenium은 자동화 테스트를 위한 도구로 만들어졌다.

하지만 이것으로 매크로도 만들고 크롤러도 만들 수 있다.

 

 

파이썬 코딩

selenium은 Java, Python, C#, Ruby, Javascript, Kotlin를 지원한다고 하는데 Python이 가장 쉬운 것 같고 자료도 많고 예전에 크롤러 만들 때 파이썬을 만들어 보아서 파이썬을 선택했다.

 

selenium pakage 설치

pip3 install selenium

 

전체코드

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from time import sleep

ser = Service("/Users/han/Downloads/jj/chromedriver") # chromedriver가 있는 디렉터리 경로
op = webdriver.ChromeOptions()
chrome = webdriver.Chrome(service=ser, options=op)
chrome.get('https://safety.konkuk.ac.kr/ushm/edu/online.do') # 안전교육 URL
idinput = chrome.find_element_by_xpath('//*[@id="userId"]')
idinput.send_keys('input your ID') # ID 입력하기
pwinput = chrome.find_element_by_xpath('//*[@id="userName"]')
pwinput.send_keys('input your PW') # PW 입력하기
chrome.find_element_by_xpath('//*[@id="btnUser"]').click()
chrome.get('https://safety.konkuk.ac.kr/ushm/edu/online.do')
chrome.implicitly_wait(3)

for a in range(2,9):
    while(True):
        btn = chrome.find_element_by_xpath('//*[@id="tblProgressList"]/tbody/tr['+str(a)+']/td[7]/input')
        print('("******************'+str(a)+'btn.text', btn.get_attribute('value'))
        if(btn.get_attribute('value') == '다시보기'):
            break
        btn.click()
        chrome.implicitly_wait(3)
        chrome.switch_to.window(chrome.window_handles[-1])
        now = int(chrome.find_element_by_css_selector('#footer > div > div.pageNumDiv > div.pageNum.cPageNum').text)
        num = int(chrome.find_element_by_css_selector('#footer > div > div.pageNumDiv > div.pageNum.tPageNum').text)
        print("******************now",now)
        print("******************num",num)
        dtime = chrome.find_element_by_css_selector('#footer > div > div.timeDiv > div.dTime').text.split(':')
        playTime = int(dtime[0])*60 + int(dtime[1]) + 3
        sleep(playTime)
        print("******************playTime",playTime)
        chrome.close()
        chrome.switch_to.window(chrome.window_handles[-1])
        if(now == num):
            break

 

import

from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from time import sleep

위에서 두 줄은 selenimum을 가져오는 것이다.

sleep은 강의 플레이 타임 만큼 기다려야 할 때를 위한 것이다.

 

driver 세팅

ser = Service("/Users/han/Downloads/jj/chromedriver") # chromedriver가 있는 디렉터리 경로
op = webdriver.ChromeOptions()
chrome = webdriver.Chrome(service=ser, options=op)

다운 받은 크롬 드라이버의 경로와 옵션을 지정해준다. 여기서는 지정해준 옵션이 없다. 

 

로그인

chrome.get('https://safety.konkuk.ac.kr/ushm/edu/online.do') # 안전교육 URL
idinput = chrome.find_element_by_xpath('//*[@id="userId"]')
idinput.send_keys('input your ID') # ID 입력하기
pwinput = chrome.find_element_by_xpath('//*[@id="userName"]')
pwinput.send_keys('input your PW') # PW 입력하기
chrome.find_element_by_xpath('//*[@id="btnUser"]').click()

안전교육 사이트에 접속해서 ID, PW를 입력하고 로그인 버튼을 누른다.

 

강의 열기

chrome.get('https://safety.konkuk.ac.kr/ushm/edu/online.do')
chrome.implicitly_wait(3)

for a in range(2,8):
    while(True):
        btn = chrome.find_element_by_xpath('//*[@id="tblProgressList"]/tbody/tr['+str(a)+']/td[7]/input')
        print('("******************'+str(a)+'btn.text', btn.get_attribute('value'))
        if(btn.get_attribute('value') == '다시보기'):
            break
        btn.click()
        chrome.implicitly_wait(3)
        chrome.switch_to.window(chrome.window_handles[-1])

강의 선택 화면으로 이동한 후

2 ~ 7까지 총 6개의 강의를 들을 것이다.

다만, 이미 강의 수강을 완료해서 '다시보기'라고 표시되는 강의는 스킵한다.

 

여기서 중요한 selenium 코드 두개가 나온다. 

chrome.implicitly_wait(3):

최대 3초간 기다리면서 페이지가 로딩될 때까지 기다려준다. element를 찾을 때 이 코드 없이 찾으면 종종 element를 찾을 수 없다는 오류가 발생한다. 

 

chrome.switch_to.window(chrome.window_handles[-1])

현재 보고 있는 창을 새로 열린 창으로 바꾼다. 이렇게 해야 강의 플레이어를 제어할 수 있게 된다.

 

플레이 타임 계산하기

        now = int(chrome.find_element_by_css_selector('#footer > div > div.pageNumDiv > div.pageNum.cPageNum').text)
        num = int(chrome.find_element_by_css_selector('#footer > div > div.pageNumDiv > div.pageNum.tPageNum').text)
        print("******************now",now)
        print("******************num",num)
        dtime = chrome.find_element_by_css_selector('#footer > div > div.timeDiv > div.dTime').text.split(':')
        playTime = int(dtime[0])*60 + int(dtime[1]) + 3
        sleep(playTime)
        print("******************playTime",playTime)
        chrome.close()
        chrome.switch_to.window(chrome.window_handles[-1])
        if(now == num):
            break

now는 현재 얼마나 들었는지 num은 앞으로 남은 페이지를 표시하는 element이다. 이 element의 텍스트를 가져와서 현재 강의를 완료했는지 판단할 것이다. 

dtime은 현재 페이지의 플레이 타임이다. 플레이 타임을 초 단위로 계산해서 sleep()해준다.

그 후, 강의 플레이어를 닫는다. now와 num 같이 같으면 강의 수강을 완료한 것이고 아니면 위 과정을 반복한다.

 

어려웠던 점

1. 플레이어 내에서 다음 버튼을 클릭할 수 없었다.

div버튼이라 클릭할 수 없었던 것 같았다.

플레이타임을 꽉 채우고 플레이어를 닫았다 열면 다음 페이지로 자동으로 이동되어서 플레이어를 닫았다 여는 방식으로 해결하였다.

 

2. 중간에 돌발 퀴즈를 누를 수 없었다.

이것은 어쩔 수 없이 수동으로 넘겨주어야 했다. ㅠㅠ