메뉴 닫기

파이썬 Selenium Shadow DOM 접근 방법 host shadow_root 활용 가이드

파이썬 Selenium Shadow DOM 접근 방법 host shadow_root 활용 가이드

🚀 Selenium으로 Shadow DOM 내부 요소 탐색하는 실전 예제와 꿀팁

웹 자동화 작업을 하다 보면 일반적인 DOM 접근만으로는 원하는 요소를 찾을 수 없는 경우가 있습니다.
특히 최신 웹 애플리케이션에서는 Shadow DOM을 활용해 컴포넌트가 구성되는 경우가 많죠.
이럴 때 Selenium을 그대로 사용하면 요소 탐색이 제대로 되지 않아 난관에 부딪히곤 합니다.
프론트엔드 개발자뿐만 아니라 자동화 테스트를 진행하는 QA 엔지니어, 그리고 데이터 크롤링을 하는 분들에게도 이는 큰 도전 과제가 됩니다.

다행히 Selenium에서는 Shadow Root를 활용하여 내부 요소에 접근할 수 있는 방법을 제공합니다.
즉, 단순히 find_element로는 접근할 수 없지만, host 요소에서 shadow_root 객체를 호출하면 내부 탐색이 가능해집니다.
오늘은 바로 이 host.shadow_root.find_element 방식을 중심으로, Python Selenium을 통해 Shadow DOM 내부에 접근하는 법을 쉽고 명확하게 정리해 드리겠습니다.



🔎 Shadow DOM이란 무엇인가?

웹 개발에서 Shadow DOM은 컴포넌트 기반 UI를 구현하기 위한 핵심 기술입니다.
브라우저가 제공하는 캡슐화 메커니즘으로, 각 컴포넌트가 독립적인 DOM 구조와 스타일을 가질 수 있도록 도와줍니다.
쉽게 말해, 외부의 CSS나 스크립트가 의도치 않게 영향을 미치지 않도록 보호해 주는 일종의 ‘작은 DOM 세계’라고 할 수 있죠.

예를 들어, 크롬 브라우저의 주소창 UI나 기본 제공되는 HTML 요소 일부는 Shadow DOM을 활용해 렌더링됩니다.
이 덕분에 사용자 정의 CSS로 브라우저 핵심 UI를 쉽게 변경할 수 없게 보호되는 셈입니다.
또한 최근 프론트엔드 프레임워크(예: Lit, Stencil, Web Components)에서 제공하는 재사용 가능한 위젯도 Shadow DOM을 적극적으로 활용합니다.

📌 왜 Selenium에서 Shadow DOM이 문제일까?

기본적인 find_element 메서드는 일반 DOM 구조에서만 동작합니다.
하지만 Shadow DOM 내부는 별도의 트리로 관리되기 때문에, Selenium이 이를 직접 인식하지 못합니다.
따라서 단순히 driver.find_element()를 실행하면 Shadow DOM 내부 요소는 “찾을 수 없다”는 오류가 발생하죠.

⚠️ 주의: Shadow DOM 내부 요소에 직접 접근하려 하면 Selenium은 DOM을 탐색할 수 없기 때문에 NoSuchElementException 오류가 발생할 수 있습니다.

📌 Shadow DOM의 장점

  • 🔒스타일과 스크립트가 외부에 영향을 받지 않으므로 안정적인 UI 유지 가능
  • 📦컴포넌트 단위의 재사용성 극대화
  • 대규모 애플리케이션에서도 효율적인 유지보수 가능

즉, 개발자와 사용자 모두에게 유리한 구조이지만, 자동화 테스트나 크롤링 작업에서는 반드시 전용 접근 방식을 사용해야 한다는 점을 기억해야 합니다.

⚙️ Selenium에서 Shadow Root 접근하기

Selenium은 기본적으로 Shadow DOM 내부를 탐색할 수 없습니다.
하지만 Python Selenium 4부터는 shadow_root 속성을 활용하여 호스트 요소 내부에 접근할 수 있는 기능을 지원합니다.
이 기능을 활용하면 일반 DOM처럼 find_element 메서드로 Shadow DOM 안쪽을 탐색할 수 있죠.

접근 절차는 비교적 단순합니다.
먼저 Shadow DOM을 감싸는 호스트 요소를 찾은 뒤, 해당 요소의 shadow_root를 호출합니다.
그러면 별도의 DOM 트리처럼 작동하는 객체가 반환되고, 그 안에서 다시 원하는 요소를 찾을 수 있습니다.

📌 기본 접근 방식

CODE BLOCK
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://example.com")

# Shadow host 찾기
host = driver.find_element(By.CSS_SELECTOR, "shadow-host-selector")

# Shadow root 접근
shadow = host.shadow_root

# 내부 요소 탐색
button = shadow.find_element(By.CSS_SELECTOR, "button.submit")
button.click()

위 코드에서 핵심은 host.shadow_root 부분입니다.
이 과정을 거쳐야만 Shadow DOM 내부 요소를 Selenium이 인식할 수 있습니다.

📌 JavaScript 실행 방식과 비교

Selenium 4 이전에는 Shadow DOM 접근을 위해 execute_script를 사용해야 했습니다.
즉, JavaScript를 직접 실행해 shadowRoot 객체를 반환받는 방식이었죠.
그러나 이제는 shadow_root 속성이 정식으로 지원되기 때문에 코드가 훨씬 간결해졌습니다.

💎 핵심 포인트:
Python Selenium 4부터는 별도의 JavaScript 실행 없이도 shadow_root.find_element()로 Shadow DOM 내부 탐색이 가능합니다.



🛠️ host.shadow_root.find_element 실전 코드 예제

이제 실제 Python 코드로 host.shadow_root.find_element를 어떻게 사용하는지 살펴보겠습니다.
아래 예제는 로그인 버튼이 Shadow DOM 안에 위치한 경우, 해당 버튼을 찾아 클릭하는 과정을 보여줍니다.

CODE BLOCK
from selenium import webdriver
from selenium.webdriver.common.by import By

driver = webdriver.Chrome()
driver.get("https://example.com")

# Shadow host 찾기
host = driver.find_element(By.CSS_SELECTOR, "login-component")

# Shadow root 접근
shadow = host.shadow_root

# 내부 버튼 탐색
login_button = shadow.find_element(By.CSS_SELECTOR, "button#login")
login_button.click()

위 코드를 실행하면 Shadow DOM 내부에 숨겨져 있던 로그인 버튼을 정확히 찾아 동작시킬 수 있습니다.
만약 여러 개의 Shadow DOM이 겹쳐 있는 경우에는, 단계적으로 각 shadow_root를 탐색해야 합니다.

📌 코드 적용 시 유의사항

  • Shadow DOM이 렌더링되기 전에 접근하면 NoSuchElementException 발생
  • 🔄반드시 WebDriverWait를 사용해 요소가 로드될 때까지 대기
  • 🧩중첩 구조에서는 단계별로 shadow_root를 탐색해야 함

💬 실전에서는 단순 클릭 외에도 입력창 탐색, 속성 값 읽기, 이벤트 트리거 등 다양한 활용이 가능합니다.

🔌 중첩된 Shadow DOM 탐색 방법

실제 웹사이트에서는 Shadow DOM이 한 겹만 있는 경우보다 중첩된 구조를 가진 경우가 많습니다.
이때는 첫 번째 Shadow DOM에 접근한 뒤, 다시 내부에 존재하는 Shadow Host를 찾아 또다시 shadow_root로 들어가야 합니다.
즉, 단계별 탐색이 필수라는 뜻입니다.

📌 중첩 Shadow DOM 예제 코드

CODE BLOCK
# 1차 Shadow host 찾기
outer_host = driver.find_element(By.CSS_SELECTOR, "outer-component")
outer_shadow = outer_host.shadow_root

# 2차 Shadow host 찾기
inner_host = outer_shadow.find_element(By.CSS_SELECTOR, "inner-component")
inner_shadow = inner_host.shadow_root

# 내부 버튼 클릭
inner_button = inner_shadow.find_element(By.CSS_SELECTOR, "button.confirm")
inner_button.click()

위와 같이 단계별로 shadow_root 객체를 탐색해야만 중첩된 Shadow DOM 안쪽 요소를 제대로 찾을 수 있습니다.

📌 중첩 탐색 시 주의사항

💡 TIP: 중첩된 Shadow DOM을 다룰 때는 각 단계마다 WebDriverWait을 사용해 요소가 로드될 때까지 대기하는 습관이 필요합니다.

  • 🔍한 번에 깊숙한 요소를 찾으려 하지 말고, 반드시 단계적으로 접근
  • ⏱️DOM 로드 타이밍에 따라 실패할 수 있으므로 Explicit Wait 필수
  • 🧭내부에 또 다른 컴포넌트가 있는지 구조를 미리 파악

즉, 중첩 Shadow DOM은 단순히 한 번의 접근으로 해결되지 않으며, 여러 단계의 shadow_root 탐색을 통해 원하는 요소를 찾아야 합니다.



💡 자주 발생하는 오류와 해결법

Shadow DOM을 Selenium으로 다루다 보면 예상치 못한 오류가 자주 발생합니다.
특히 DOM 로딩 타이밍이나 셀렉터 지정 문제로 인해 테스트가 실패하는 경우가 많습니다.
아래에서는 실무에서 자주 마주치는 오류와 그 해결 방법을 정리했습니다.

📌 NoSuchElementException

Shadow DOM 내부 요소가 로드되기 전에 접근하려 하면 발생합니다.
이 문제는 WebDriverWait을 사용하여 요소가 나타날 때까지 기다리면 해결됩니다.

CODE BLOCK
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
host = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "shadow-host")))

📌 StaleElementReferenceException

DOM이 리렌더링되면서 기존에 참조하던 요소가 사라질 때 발생합니다.
이 경우에는 다시 find_element로 요소를 탐색해야 합니다.

⚠️ 주의: React, Vue 같은 프레임워크 기반 웹사이트에서는 Shadow DOM 내부가 자주 갱신되므로 재탐색 로직을 반드시 준비해야 합니다.

📌 CSS Selector 불일치

Shadow DOM 내부의 구조는 일반 DOM과 다를 수 있으므로 CSS 선택자가 조금만 틀려도 요소를 찾지 못합니다.
따라서 개발자 도구에서 반드시 shadow-root 내부 구조를 확인하고 올바른 셀렉터를 지정해야 합니다.

💎 핵심 포인트:
Selenium에서 Shadow DOM 오류를 해결하려면 대기(WebDriverWait), 재탐색, 정확한 셀렉터 이 세 가지가 핵심입니다.

자주 묻는 질문 (FAQ)

Selenium에서 Shadow DOM은 꼭 shadow_root를 사용해야 하나요?
네, 기본적인 find_element 메서드만으로는 Shadow DOM 내부 요소를 탐색할 수 없습니다. 반드시 host.shadow_root를 통해 접근해야 합니다.
중첩된 Shadow DOM도 Selenium으로 탐색 가능한가요?
가능합니다. 다만 단계별로 각 shadow_root를 거쳐 들어가야 하며, 한 번에 내부까지 직접 접근할 수는 없습니다.
JavaScript 실행으로도 Shadow DOM에 접근할 수 있나요?
네, execute_script를 사용해 shadowRoot 객체를 반환받을 수도 있습니다. 하지만 Selenium 4부터는 shadow_root 속성을 사용하는 것이 더 간단하고 직관적입니다.
Shadow DOM 내부의 CSS 선택자는 일반 DOM과 동일한가요?
동일한 CSS 선택자 규칙을 따릅니다. 하지만 반드시 shadow-root 내부 구조를 확인한 후에 정확한 선택자를 사용해야 합니다.
Selenium에서 Shadow DOM 접근 시 가장 흔한 오류는 무엇인가요?
가장 흔한 오류는 NoSuchElementException과 StaleElementReferenceException입니다. 이는 대기 처리와 재탐색 로직으로 해결할 수 있습니다.
WebDriverWait은 왜 필요한가요?
Shadow DOM 내부 요소는 렌더링이 지연될 수 있기 때문에, 반드시 WebDriverWait으로 요소가 로드될 때까지 기다려야 안정적인 테스트가 가능합니다.
React나 Vue 같은 프레임워크에서도 동일하게 동작하나요?
네, Shadow DOM을 사용하는 한 원리는 동일합니다. 다만 프레임워크 특성상 DOM이 자주 리렌더링되므로 재탐색 로직을 더 자주 활용해야 합니다.
Selenium 말고 다른 도구에서도 Shadow DOM 접근이 가능한가요?
네, Playwright나 Puppeteer 같은 최신 자동화 도구들도 Shadow DOM 접근을 지원합니다. 경우에 따라 더 직관적인 API를 제공하기도 합니다.

📌 Selenium으로 Shadow DOM 내부 탐색 완벽 정리

오늘은 Python Selenium을 활용하여 Shadow DOM 내부 요소 탐색 방법을 단계별로 정리했습니다.
기본적인 개념부터 시작해, host.shadow_root.find_element의 활용법, 중첩된 Shadow DOM 탐색 방식, 그리고 자주 발생하는 오류 해결법까지 살펴봤습니다.
특히 Selenium 4에서 제공하는 shadow_root 속성은 기존의 JavaScript 실행 방식보다 훨씬 직관적이고 간결한 코드 작성이 가능하다는 장점이 있습니다.

정리하자면, 안정적인 Shadow DOM 자동화를 위해서는 단계적 접근, WebDriverWait 활용, 그리고 정확한 CSS 선택자 지정이 필수입니다.
이 세 가지 원칙만 잘 지킨다면, 복잡한 Shadow DOM 구조를 가진 웹사이트에서도 Selenium을 활용한 자동화가 충분히 가능합니다.


🏷️ 관련 태그 : Selenium, Python자동화, ShadowDOM, 웹테스트, hostshadowroot, findelement, 웹크롤링, 자동화스크립트, QA테스트, 웹컴포넌트