Selenium WebDriver로 웹 자동화를 하다 보면, WebDriver가 제공하는 메서드만으로는 안 되는 조작이 있습니다. 요소의 임의 속성을 직접 바꾸거나, 화면에 안 보여서 클릭이 안 되는 요소를 억지로 눌러야 할 때죠. 이럴 때 IJavaScriptExecutor 로 브라우저 안에서 자바스크립트를 실행하면 DOM을 직접 건드릴 수 있습니다. 아래는 어떤 a 태그 요소의 className 과 innerHTML 을 바꾼 뒤 클릭하는 코드입니다.
'LinkTextElement.setAttribute("value", "80")
Dim je As IJavaScriptExecutor = CType(IE, IJavaScriptExecutor)
href = je.ExecuteScript("return arguments[0].className;", LinkTextElement)
Clipboard.SetText(href)
je.ExecuteScript("return arguments[0].className = '" & Split(href, ",r:").First & ",r:10'" & ";", LinkTextElement)
je.ExecuteScript("return arguments[0].innerHTML = '" & 10 & "'" & ";", LinkTextElement)
href = je.ExecuteScript("return arguments[0].className;", LinkTextElement)
LinkTextElement.Click()
여기서 LinkTextElement 는 미리 찾아 둔 a 태그 요소입니다.
arguments[0] 가 뭔가
IJavaScriptExecutor 는 WebDriver 객체(IE)를 형변환해서 얻습니다. ExecuteScript 의 첫 인자가 실행할 스크립트, 두 번째 인자부터가 그 스크립트에 넘길 값인데, 넘긴 값들은 스크립트 안에서 arguments[0], arguments[1] 로 받습니다. 그래서 je.ExecuteScript("return arguments[0].className;", LinkTextElement) 는 "넘긴 요소의 className을 돌려줘"라는 뜻입니다. 요소를 셀렉터로 다시 찾지 않고 이미 가진 요소를 그대로 넘길 수 있다는 게 이 방식의 장점입니다.
이 코드의 흐름은 이렇습니다. 먼저 요소의 현재 className 을 읽어 클립보드에 넣어 두고(확인용), 그 값에서 ,r: 뒤를 잘라 내고 ,r:10 으로 바꿔 다시 넣습니다. 이어서 보이는 글자(innerHTML)를 10 으로 바꾸고, 바뀐 className 을 다시 읽어 확인한 뒤 클릭합니다. ,r: 로 나눠 끝 값만 교체하는 걸 보면, 이 사이트는 페이지 번호나 개수 같은 설정이 요소의 클래스 이름 안에 들어 있는 구조로 보입니다. 그래서 이 코드 자체는 그 특정 페이지에만 맞는 조작이고, 일반적인 링크에 그대로 쓰긴 어렵습니다.
고쳐 두면 좋은 부분
ExecuteScript("return arguments[0].className = '...';", ...) 처럼 return 뒤에 대입문을 쓰면 대입한 값이 반환됩니다. 동작은 하지만 의도가 불분명하니, 값을 바꾸기만 할 거면 return 없이 arguments[0].className = arguments[1]; 로 쓰고 새 값은 인자로 넘기는 게 깔끔합니다.
je.ExecuteScript("arguments[0].className = arguments[1];", LinkTextElement, newClassName)
je.ExecuteScript("arguments[0].innerHTML = arguments[1];", LinkTextElement, "10")
원 코드처럼 VB 문자열을 이어 붙여 스크립트를 만들면, 끼워 넣는 값에 작은따옴표나 줄바꿈이 들어갈 때 스크립트가 깨집니다. 값은 위처럼 arguments 로 넘기는 편이 안전합니다.
그리고 innerHTML 에 사용자 입력 같은 걸 넣으면 그 안의 태그가 실제 HTML로 해석됩니다. 단순 텍스트만 바꿀 거면 innerHTML 대신 textContent 를 쓰세요. 주석 처리된 setAttribute("value", "80") 은 a 태그에는 value 속성이 없어서 효과가 없으니, 그래서 자바스크립트 방식으로 바꾼 것으로 보입니다. 마지막으로, 이렇게 DOM을 강제로 바꾼 뒤 클릭하는 방식은 페이지가 조금만 바뀌어도 깨지니, 가능하면 사이트가 정식으로 제공하는 조작(옵션 선택 등)을 먼저 찾아보는 게 유지보수에 낫습니다.