
10년 동안 품어온 'Excel로 RPA'를 AI와 함께 2시간 만에 구현한 이야기
요약
Windows 기본 기능인 UI Automation과 PowerShell을 활용하여 별도의 설치 없이 Excel VBA로 RPA를 구현하는 방법을 소개합니다. 기존의 불안정한 SendKeys 방식이나 설치가 필요한 Selenium 대신, 윈도우 표준 메커니즘을 이용해 안정적인 자동화를 달성한 사례를 다룹니다.
핵심 포인트
- Windows 기본 UI Automation을 활용해 설치 없는 RPA 구현 가능
- VBA에서 직접 호출 대신 PowerShell을 매개체로 사용하여 제약 해결
- SendKeys 방식의 불안정성(맹타)을 극복하는 객체 기반 제어
- IE 종료 이후의 대안으로 브라우저 및 데스크톱 앱 자동화 가능
파일 목록 북마크를 만들던 시절부터 계속 생각해 온 것이 있습니다.
Excel에서 다른 소프트웨어를 움직일 수 없을까.
하고 싶은 일은 단순합니다. Excel에 나열된 데이터를 다른 소프트웨어의 입력란에 흘려넣고 싶습니다. 세상에서는 그것을 RPA라고 부르며, 전용 소프트웨어를 구매하여 로봇이 화면을 조작하게 합니다. 구매하지 않고 Excel 안에서 할 수는 없을까── 그렇게 생각하며 10년 가까이 손을 대지 못하고 있었습니다.
얼마 전, AI와 다른 작업을 하던 흐름에서 문득 그 이야기가 나왔습니다. 거기서부터 두 시간 정도 만에, 작동하는 단계까지 도달했습니다.
게다가 아무것도 사지 않았습니다. 아무것도 설치하지 않았습니다. 사용한 것은 Windows에 처음부터 들어있는 것뿐입니다.
지난번에는 API 키를 넣으려다 창고에서 꺼낸 북마크가 키째로 필요 없게 된 이야기를 썼습니다.
이번에도 「설치하지 않고 끝내는」 이야기입니다. 지난번에는 키였지만, 이번에는 도구 그 자체였습니다.
- Windows에는 UI Automation이라는 메커니즘이 처음부터 들어있습니다. 화면의 부품을 좌표가 아닌 이름으로 잡아내어, 누르거나 문자를 입력하거나 읽을 수 있습니다.
- 이것은 RPA 제품이 내부에서 사용하고 있는 것과 같습니다. 즉, RPA의 심장부는 처음부터 수중에 있었다는 뜻이 됩니다. - 단, VBA에서
CreateObject로는 호출할 수 없습니다. ProgID가 등록되어 있지 않기 때문이며, 레지스트리를 확인하여 이를 확인했습니다. - PowerShell을 한 단계 거치면 통과합니다. PowerShell도 Windows 표준이므로, 결국 설치는 제로입니다. - 실측 1: Excel 매크로에서 계산기를 지목하여 조작하고, 7+3=10을 누르게 한 뒤 표시된 값을 읽어오는 것까지 1.4초 - 실측 2: 브라우저 입력란에 문자를 넣고, 버튼을 누르고, 화면에 나온 결과를 읽어오는 것까지 성공
- 브라우저에는 함정이 있었습니다. 일반적으로 연 창에서는 페이지의 내용이 전혀 보이지 않습니다. 실행 시 옵션을 하나 추가해야 합니다.
- 부품은 모두 이미 공개되어 있습니다. 제가 한 것은 그것들을 연결하여 Excel에서 쏠 수 있는 형태로 만든 것뿐입니다.
먼저, 지금까지 무엇을 할 수 없었는지 적겠습니다.
「Excel VBA로 RPA」를 검색하면 기사나 영상이 제법 나옵니다. 하지만 내용을 보면 대부분 SendKeys입니다. 목적의 윈도우를 전면으로 내세우고, 키보드 문자를 보내는 방식입니다.
저는 이것을 **맹타 (Blind Typing)**라고 부릅니다. 눈을 감고 그곳에 있을 법한 위치를 두드리고 있기 때문입니다.
맹타에는 약점이 있습니다. 윈도우가 전면에 나와 있지 않으면 문자는 엉뚱한 곳으로 날아갑니다. 상대가 아직 로딩 중이라면 헛스윙을 합니다. 입력란으로 이동하기 위해 Tab을 몇 번 눌러야 할지는 상대 화면의 구성에 달려 있습니다. 잘 될지 안 될지가 그때그때 화면의 기분(상태)에 좌우됩니다.
브라우저가 상대라면 과거에는 다른 길이 있었습니다. Internet Explorer입니다. CreateObject("InternetExplorer.Application") 한 줄로 브라우저를 손에 넣을 수 있었고, 페이지의 내용을 직접 만질 수 있었습니다. 그것은 정말 잘 만들어져 있었습니다.
그 IE가 2022년 6월에 종료되었습니다.
대체제로 안내되는 것은 Selenium Basic입니다. 다만 이것은 설치가 필요합니다. 게다가 본체의 업데이트는 수년째 멈춰 있습니다.
즉, 「설치하지 않고 브라우저를 조작하는 길」은 지난 4년 정도 비어 있는 상태였습니다.
여기서부터가 본론입니다.
Windows에는 UI Automation이라는 메커니즘이 들어있습니다. 원래는 시각 장애인이 화면 읽기 소프트웨어를 사용하기 위한 토대입니다. 화면의 부품에 이름과 종류를 부여하여 외부에서 꺼낼 수 있도록 해두었습니다.
그리고 RPA 제품은 이것을 자사의 화면으로 감싸서 판매하고 있습니다. 부품을 이름으로 잡아내고, 누르고, 읽는── 제품이 하고 있는 일의 핵심은 바로 이 메커니즘입니다.
즉, 심장부는 처음부터 모든 사람의 PC에 탑재되어 있었습니다.
맹타와의 차이는 결정적입니다.
| 구분 | 맹타 (SendKeys) | 지목 (UI Automation) |
|---|---|---|
| 무엇을 지정하는가 | 전면 윈도우 + 키의 나열 | 부품의 이름 |
| ... | ... | ... |
좌표를 때리는 것이 아니라 이름을 부르는 것. 부르면 대답이 있다. 이것이 이번 이야기의 핵심입니다.
곧바로 VBA에서 호출하려고 시도했습니다. 제 방식에서는 외부 부품은 반드시 CreateObject
로 호출합니다. 참조 설정 (Reference Setting)에 의존하면, 배포한 통합 문서가 상대방의 환경에서 작동하지 않게 되기 때문입니다.
제가 작성한 것은 이것뿐이어야 했습니다.
Set uia = CreateObject("UIAutomationClient.CUIAutomation")
작동하지 않습니다. 단계를 기록하는 진단 매크로를 넣어 실행해 보니, 첫 번째 단계에서 멈춰 있었습니다.
만약을 위해 클래스의 식별 번호를 직접 지정하는 우회 방법도 시도했습니다. 이 또한 안 되었습니다.
그래서 레지스트리를 확인하러 갔습니다. 답은 그곳에 있었습니다.
{ff48dba4-60ef-4201-aa87-54103eef594e}
ProgID = [] ← 빈 값
DLL = C:\Windows\System32\uiautomationcore.dll
...
부품은 등록되어 있고, 본체 DLL도 있습니다. 하지만 이름 (ProgID)이 붙어 있지 않습니다.
CreateObject는 이름으로만 호출할 수 있는 함수입니다. 이름이 없는 부품은 이 입구를 통해서는 호출할 수 없습니다. 참조 설정을 사용한다면 별개의 문제지만, 그렇게 하면 배포 가능한 통합 문서가 되지 않습니다.
소개된 기사는 몇 가지 있지만, 제가 본 범위 내에서는 참조 설정을 활성화하는 것을 전제로 한 것들이었습니다. 왜 CreateObject로는 안 되는지를 쓴 글은 찾을 수 없었습니다. 이 부분은 실물로 직접 확인할 수밖에 없었습니다.
막혀 있는 것은 VBA로부터의 직통 경로뿐입니다. 다른 길을 찾으면 됩니다.
PowerShell이라면 이 메커니즘을 처음부터 다룰 수 있습니다. 게다가 PowerShell은 Windows 표준입니다. 추가로 설치할 것도 없습니다.
Add-Type -AssemblyName UIAutomationClient
Add-Type -AssemblyName UIAutomationTypes
$root = [System.Windows.Automation.AutomationElement]::RootElement
실행해 보니, 단번에 화면의 창들이 전부 나열되었습니다.
[Chrome_WidgetWin_1] Claude
[XLMAIN] 秀 - コピー (2).xlsm - Excel
[Progman] Program Manager
통과했습니다.
남은 것은 Excel과의 연결 방법입니다. 이것은 고민할 필요가 없었습니다. 이미 같은 형태를 가지고 있었기 때문입니다.
이전에 Excel의 폼에서 AI를 호출하는 도구를 만들었을 때, 다음과 같은 절차를 구성했습니다.
- VBA가 전달하고 싶은 내용을 파일로 작성한다
- 외부 프로그램을 화면 표시 없이 실행한다
- VBA는
DoEvents로 루프를 돌며 결과 파일이 나오기를 기다린다 - 파일이 나오면 읽어 들인다
이 네 단계가 그대로 사용 가능합니다. 호출하는 대상이 AI에서 PowerShell로 바뀔 뿐입니다.
첫 번째 대상은 계산기로 정했습니다.
시키는 일은 7을 누르고, +를 누르고, 3을 누르고, =를 누른 뒤, 표시된 답을 읽어오는 것입니다. RPA가 업무에서 하는 일의 축소판입니다.
VBA 측은 이런 구조입니다. 요점만 뽑겠습니다.
Sub 계산기 조종하기()
' (1) PowerShell 스크립트를 구성하여 UTF-8로 작성한다
ps = ps & "Add-Type -AssemblyName UIAutomationClient" & vbCrLf
...
CreateObject만을 사용했습니다. 참조 설정은 전혀 없습니다.
PowerShell 측은 누를 버튼의 이름을 나열하여 차례대로 누를 뿐입니다.
foreach ($id in @('clearButton','num7Button','plusButton','num3Button','equalButton')) {
$b = $w.FindFirst($TS::Descendants, (이름이 $id라는 조건))
$b.GetCurrentPattern([System.Windows.Automation.InvokePattern]::Pattern).Invoke()
...
plusButton이라고 쓰면 + 버튼이 눌립니다. 좌표는 단 하나도 쓰지 않았습니다.
창을 찾는 방법도 고안했습니다. '계산기'라는 표시 이름으로 찾는 것이 아니라, 내부에 num7Button을 가지고 있는 창을 계산기로 판정합니다. 표시 이름이 바뀌어도 찾아낼 수 있습니다.
실행했습니다.
계산기 조작 1.4초 → 표시값은 10입니다
1.4초. 버튼을 누르게 하고, 다시 읽어올 때까지의 시간입니다. 계산기는 눈앞에서 실제로 움직입니다.
본론은 이겁니다. 요즘 업무용 화면은 브라우저에서 동작하는 것이 많기 때문에, 이 부분이 통과되지 않으면 활용도가 절반으로 줄어듭니다.
직접 테스트용 페이지를 만들었습니다. 입력란 2개와 버튼 1개를 배치한 것뿐인, 십수 줄짜리 간단한 페이지입니다. 버튼을 누르면 입력한 글자를 그대로 화면에 표시합니다.
브라우저로 열어서, 아까와 같은 방식으로 내부를 들여다보았습니다.
Edit 요소 = 2 개
name=[주소 및 검색바]
name=[]
페이지 내용이 나오지 않습니다. 브라우저 자체의 주소창은 가져올 수 있는데, 제가 배치한 입력란이 보이지 않습니다. 버튼 쪽도 가져올 수 있는 것은 「최소화」, 「뒤로 가기」, 「즐겨찾기」와 같은 브라우저 부품뿐입니다.
조사해 보니 알게 되었습니다. 현재의 브라우저는, 스크린 리더(Screen Reader)와 같은 상대가 왔다고 판단하기 전까지 페이지 내용을 외부에 공개하지 않습니다. 항상 공개하고 있으면 무거워지기 때문에, 필요할 때만 만들도록 설계되어 있습니다.
외부에서 깨우려면, 실행할 때 옵션을 하나 추가해야 합니다.
--force-renderer-accessibility
이 옵션을 붙여서, 전용 설정으로 창을 하나 다시 띄웠습니다. 마찬가지로 들여다봅니다.
Edit 요소 = 4 개
name=[주소 및 검색바]
name=[제목] autoId=[...]
...
나왔습니다.
게다가 기쁜 발견이 있었습니다. HTML의 id가 그대로 잡기 위한 이름이 되어 있습니다. 페이지 제작자가 입력란에 붙인 이름을 그대로 지정할 수 있다는 뜻입니다.
남은 것은 입력하고, 누르고, 읽는 것뿐이었습니다.
# 입력란에 글자를 넣음
$k.GetCurrentPattern([System.Windows.Automation.ValuePattern]::Pattern).SetValue("(샘플 문자열)")
# 버튼을 누름
...
결과입니다.
입력란 내용 = [(샘플 문자열)]
화면 표시 = 등록되었습니다: (샘플 문자열)
입력·실행·읽어오기. 세 가지 모두 통과했습니다.
참고로, 이 옵션에 관한 이야기는 RPA 제품의 공식 문서에 적혀 있습니다. 브라우저 버전에 따라 동작 방식이 변했던 시기도 있었던 모양인지, 그 경위까지 공개되어 있었습니다. 업계에서는 상식에 속하는 부분입니다. 모르고 시도했다면 "브라우저는 무리였습니다"라며 끝났을 일입니다.
10년 동안 생각했던 것이 왜 오늘 가능했는지 정리하겠습니다.
구조는 훨씬 전부터 있었습니다. UI Automation은 새로운 것이 아닙니다. 제가 몰랐을 뿐입니다.
막혀 있었던 것은 입구였습니다. VBA에서 직접 호출할 수 없다는 점 하나 때문에, VBA만 쓰는 사람은 입구 앞에서 멈춥니다. 저도 멈춰 있었습니다.
열린 것은 우회로를 생각해낸 것이었습니다. 그리고 그 우회로는 AI를 호출하기 위해 작년부터 사용했던 방식과 완전히 같은 형태였습니다. 새롭게 배운 것은 사실 아무것도 없습니다. 가지고 있던 부품의 방향을 바꿨을 뿐입니다.
그렇게 생각하니 AI와 함께 해서 빨랐던 이유도 명확합니다. "레지스트리를 보고 이름이 붙어 있지 않음을 확인한다", "다른 통로를 찾는다", "브라우저가 내용을 숨기고 있는 이유를 조사한다"── 하나하나 보면 대단한 이야기가 아니지만, 모르는 땅에서는 각각 반나절씩 잡아먹는 종류의 일들입니다. 그것들이 연달아 해결되었기에 2시간 만에 도착할 수 있었습니다.
늘 그렇듯 분류하겠습니다.
사실: UI Automation 클래스가 레지스트리에 등록되어 있고, ProgID가 비어 있다는 것(실물 확인). CreateObject 및 식별 번호의 직접 지정 모두 실패한다는 것(실측). PowerShell을 경유하면 성공한다는 것(실측). Excel 매크로에서 계산기를 조작하여 결과를 읽어올 때까지 1.4초였다는 것(Timer 측정·공개 전 재확인). 브라우저에서 옵션 없이는 입력란을 가져올 수 없으며, --force-renderer-accessibility를 붙이면 가져올 수 있다는 것(동일 페이지에서 전후 비교). HTML의 id가 잡기 위한 이름으로 나온다는 것(실측). IE의 지원이 2022년 6월에 종료되었다는 것. Selenium Basic 이용을 위해 설치가 필요하다는 것.
견해: 브라우저가 내부를 숨기고 있는 것은 부하를 피하기 위해서라는 설명(공개된 해설에 기반한 이해이며, 제가 직접 내부를 읽은 것은 아닙니다). "업계에서는 상식의 범주"라는 점도 공개 문서에 기재된 내용을 바탕으로 한 추측입니다. "2시간 만에 도달했다"는 내역 또한 체감일 뿐, 측정된 수치는 아닙니다.
- 부품은 모두 이미 공개되어 있습니다. VBA에서 UI Automation을 사용하는 기사도, PowerShell에서 사용하는 기사도, 브라우저의 옵션에 관한 이야기도 찾아보면 나옵니다. 제가 한 일은 그것들을 연결하여 Excel에서 실행할 수 있는 형태로 만든 것뿐입니다.
새로운 발견이 아닙니다 - 확인한 것은
Windows 11 · PowerShell 5.1 환경뿐입니다. 다른 버전은 시도하지 않았습니다 - 상대한 것은
계산기와 직접 만든 테스트 페이지입니다. 실제 업무용 소프트웨어에서 통할지는 해당 화면의 구현 방식에 따라 다릅니다. 부품에 이름이 지정되어 있지 않다면 잡을 수 없습니다 - 브라우저는
전용 실행 조건으로 띄운 창이 필요합니다. 평소 사용하는 창을 그대로 사용하는 방식은 아닙니다 - 반복 처리나 중간에 멈췄을 때의 재시작 로직은 아직 아무것도 만들지 않았습니다.
RPA 제품이 유료로 판매되는 부분은 바로 그 지점에 있습니다. 단 한 건의 전재(転記)가 성공했다고 해서 업무가 돌아가는 것은 아닙니다 - PowerShell 실행이 제한된 환경에서는 이 방법이 작동하지 않습니다. - 이번 매크로는 실험용이며, 현재로서는 공개할 예정이 없습니다. 도구들은 공개 리포지토리(Repository)에 있습니다.
10년 동안 하고 싶었던 일의 입구가, Windows 폴더 안에 계속 놓여 있었습니다.
구매해야 하는 것이라고 생각했던 것이 이미 놓여 있었습니다. 이름을 몰랐을 뿐이었습니다. 이번에 알게 된 것은 새로운 기술이 아니라, 수중에 있는 것의 이름입니다.
이름만 알면, 부르면 대답이 돌아옵니다.
그럼, 다음에 뵙겠습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기