Chrome Extension으로 강의평가 auto 프로그램 만들기...

우리 학교는 기말 성적을 보려면 강의평가를 해야한다.
근데 항목들이 수업내용과는 전혀 쌩뚱맞은 이상한 것들이여서 어차피 그냥 대충 좋음 정도로 다 클릭하는 편이다.
어차피 막 할 꺼 오토프로그램을 짜면 참 좋겠다는 생각이 들어서 Chrome Extension형태로 오토프로그램을 만들어 보기로 했다.

일단은 개발자도구를 이용해 강의평가 시스템을 분석했다.
1. 프레임들이 매우 단계적으로 쪼개져있다. saint포털 전체에서 내부적으로 여러개의 iframe이 존재하고 그안에 또 여러개의 iframe이 있고, 또 그안에 frameset/frame들이 있고... 이런 식이다...
2. 강의평가 radio button을 누를때마다, 서버로 data가 전송되고, frame이 reflesh 된다.

따라서 그냥 간단하게 나는 chrome extension에서 target frame에 접근하여 그 frame에서 getElementsByClassName 을 이용해서 radio button을 다 끍어서 체크하는 식으로 하려고 했다.
근데 chrome extension에서 security 상의 문제로 frame에 접근할 수 없었다.

참고로 chrome extension 에 대해 말하자면, 기본적으로 manifest.json 파일이 있고, 이 안에 program의 정보나 권한등을 집어넣는다. 그리고, html와 js를 통해서 program을 제작할 수 있는데, chrome extension과 web page는 서로 독립된 영역을 가진다. 따라서 각자의 code는 서로에게 영향을 끼칠 수 없다.(기본적으로는)
근데 chrome extension에서 web page의 DOM에 access 하고 싶을 때가 있다. 그 때 executeScript 라던지 content_scripts 를 사용하여 그렇게 할 수 있다. (content_scripts 를 사용하려면 permissions에 tabs를 꼭 추가해야함.)

어쨌든 다시 돌아와서 frame 내부로 접근이 불가능해서 나는 content_scripts 에서 "all_frames": true 를 해서 모든 frame에 내 script가 박히도록 했다. (그리고 "run_at": "document_idle")

근데 또 문제가 있는데 자신의 javascript 코드내에서 웹페이지 내의 javascript function 호출이 안되는 것이다.
그 이유는 chrome이 extension의 javascript code 를 sandbox에서 동작시키기 때문이다. 
그래서 이걸 우회(?) 해야하는데 일반적인 방법이 DOM에 script를 injection 해서 sandbox를 벗어나는 것이다.
그리고 좀 더 간단한 방법으로는 location.href="javascript: ~~" 를 사용하는 방법도 있다.
나는 간단하게 location.href 를 이용하는 방식으로 웹페이지 내의 function을 호출 하였다.

그리고 개발자도구를 이용해서 코드가 잘 돌아감을 테스트할 수 있었다.
근데 막상 extension을 이용해보니까 안돌아간다. 구체적으로 말해서 getElementsByClassName 이 null을 반환한다.

이때문에 한참 헤멨는데.. 나중에 알고보니 홈페이지내에서 특정 frame에서 다른 frame의 내부contents를 생성 하는 것이였다.
즉 static하게 page가 구성된게 아니라 dynamic하게 frame내부 내용이 채워졌고, 나는 document.body.innerHTML.search(~~) != -1 또는 getElementsByClassName(~~) != null 등을 가지고 코드의 실행여부를 판단했었기 때문에 당연히 target frame에서는 조건이 거짓이 되고, target frame의 내부 내용을 채워넣는 frame에서 조건이 참이 되어서 동작을 안했던 것이다. (참고로 js코드가 모든 frame에서 실행되는 상황이기때문에 js 코드의 맨 처음에서 적당히 target frame인지를 판단해줘야만한다.)
다시 말하면 프레임 A와 프레임 B가 있을 때, 프레임 A가 target frame이고 프레임 A는 딱 한 번만 request & response가 이루어진다. 그리고 radio button을 check 할때마다 프레임 B가 reflesh되고 프레임 B에서 프레임 A 내부의 contents를 다시 생성해주는 상황인 것이다.

그래서 DOMSubtreeModified event를 이용하기로 했다.
이 event는 DOM의 서브트리가 변경됬을 때 발생하는 event이다. 이를 이용해서 target frame의 내부 내용이 변경될 때 마다, 특정 함수를 실행시킬 수 있다. 물론 이 함수내부에서 document.body.innerHTML.search(~~) != -1 또는 getElementsByClassName(~~) != null 등을 이용해서 target frame인지 체크를 해줘야한다.
이렇게 하면 정확하게 target frame에 대해서만 특정 기능이 실행이 되는 js code를 만들 수 있다.

여기까지 하면 강의평가 사이트에 들어가면 자동으로 강의평가가 다 되도록 하는 크롬 익스텐션이 개발된다.
그러나 이렇게 하면 사용자가 원치 않을 때도 강의평가가 자동으로 되고, 자동으로 된 강의평가를 수정할 수 가 없어진다.
chrome extension tab을 눌렀을 때 자동으로 강의평가가 진행되도록 발전시켜보기로 했다.

이를 가능하게 하려면 message를 이용하면 된다.
content script 에서는 autoEvent 라는 이벤트를 만들고, 이 event의 listener가 위의 기능을 수행하게 한다.
그리고 message listener를 만들어서 message가 오면 autoEvent를 dispatch 시킨다.
그리고 chrome extension tab을 누르면 message를 전송하도록 코드를 짠다.
그리고 자동강의평가가 끝났을때 DOMSubtreeModified event을 delete함으로서 사용자가 추가적으로 수정할 수 있도록 한다.

강의평가에는 radio button 뿐아니라 textarea와 checkbox도 있다. 
나는 선택할 checkbox의 배열을 전역에서 random으로 생성하고, DOMSubtreeModified event listener function 내부에서 접근하는 식으로 했는데 접근은 잘 되지만 뭔가 작동이 이상했다.
그 이유는 checkbox를 누를 때 작동하는 action이 특정 프레임을 서버에서 불러오고, 그 프레임이 다시 target frame을 바꾸기전에 target frame 스스로가 살짝 바뀌어서 DOMSubtreeModified event 가 호출이 또 되는 것으로 추측된다. (check box말고 radio button 도 마찬가지임.)

 

실제로 보면 동일한 auto click 이 여러번 발생한다. 어쨌든 계획대로라면 동일한 auto click이 여러번 발생할 수 없다.
원래 생각과는 약간 다르지만 그래도 나름 잘 작동한다. (약간의 버그가 있지만 무시할 수 있다.)

근데 막상 만들고 나니 쓰려니까 죄책감이 든다 ㅋㅋㅋㅋ
그래서 그냥 나는 손으로 강평해야겠다 ㅠㅠ

크롬 익스텐션을 개발하는 게 이번이 처음인데 처음부터 뭔가 보스 몹을 만나버린 것같아서 힘들었다 ㅠㅠ
일단 자바스크립트를 야매로 알고 있어서 힘듬이 배가 됐고...ㅂㄷㅂㄷ

어쨌든 만드느라 힘들었지만, 크롬 익스텐션을 배우는 계기가 되서 좋은 경험이였던 거 같다.
그리고 추가적으로 느낀점은...
멘붕왔을때/집중안될때 하려면 6,7시간 걸릴 것을 상쾌한 상태에서 하면 1시간도 안걸린다는 점... (생산 효율이 그 얼마나 중요한가...)
항상 느끼고 알고 있는 거지만 막상 개발을 시작하면 끝내버리고 싶은 마음에 자꾸 밤을 새면서까지 한다.
그러나 비효율성의 극치... 
포기는 하지 않더라도 힘들고 머리가 아플땐 내일로 미룰 줄 아는 덕목을 길러야겠다고 다시금 마음을 먹는 계기가 됐다...

github에 가면 소스를 볼 수 있다..

댓글

  1. 저두 크롬확장으로 매크로 만드려고 했는데 좋은글 잘보고 갑니다

    답글삭제

댓글 쓰기