
어떤 필요로 웹 브라우저의 정보를 가져와야 하는 경우가 있습니다. 그럴 때 Selenium을 통해 혹은 BeautifulSoup를 가져올 것입니다. Selenium을 이용하면서 자주 보게 되는 에러가 두루 있겠지만 nosuchelementexception을 가장 많이 접할 것 같습니다.
Chrome 개발자 도구(F12)를 열어 HTML 코드를 확인하면 분명 존재하지만 읽히지 않는 element 요소들이 있습니다. 이런 경우 해당 element 요소가 shadow-root에 속해 있지는 않는지 확인을 해야 합니다.

페이지에 방문해 개발자 도구로 보면 별다른 것이 없어보이지만 위 코드에서 <onboard-v2> 태그를 열어보면 #shadow-root에 포함되어 있습니다.

이런 경우 selenium으로 바로 크롤링을 하면 element 요소를 찾지 못하게 되며 이때는 자바스크립트로 shadow DOM 객체를 찾아서 반환한 후 selenium에 전달해줘야 합니다. 다음 예제는 #shadow-root가 단일인 경우에 접근하는 방법을 제시하고 있습니다.
#shadow-root (open)
<onboard-v2>
<style>...</style>
<div1>...</div>
<div2>...</div>
</onboard-v2>
위 코드처럼 단일 #shadow-root에 감싸져있는 태그에 접근하는 것은 매우 간단합니다. 아래 코드와 같이 shadow-root 객체를 찾을 수 있는 함수를 선언합니다. 꼭 선언하지 않아도 됩니다.
def shadow_root(element):
shadow_root = driver.execute_script('return arguments[0].shadowRoot',element)
return shadow_root
이제 해당 함수를 이용해 찾고자하는 태그에 접근해야합니다. 주어진 HTML 코드에서는 <onboard-v2> 태그를 찾아야합니다.
onbord_v2 = driver.find_element(By.TAG_NAME,'onboard-v2')
그리고 div1이 필요하다면 다음 예제를 따라 수행할 수 있습니다.
div1 = shadow_root(onboard_v2)
이제 div1의 자식 요소와 본인 요소를 selenium에서 찾을 수 있습니다. 단 driver가 아닌 지정한 변수명으로 찾아야합니다.
div1.find_element(.....)
만약 첫 번째 예시처럼 단일 shadow-root가 아닌 여러 개의 shadow-root로 구성되어 있다면 차례대로 접근하여 똑같이 사용할 수 있습니다. 즉 shadow DOM을 크롤링하려면 shadow-dom 상위의 태그를 파악 한 후 반복적으로 파고들어야 합니다. 다음 예제는 3개의 shadow-root로 구성되어있는 예제를 보여주고 있습니다.
<prefix-1>
- #shadow-root
--<prefix-2>
---#shadow-root
----<prefix-3>
-----#shadow-root
------<div id="here">
prefix1 = driver.find_element(By.TAG_NAME,'prefix1')
prefix1_shadow = shadow_root(prefix1)
prefix2 = prefix1.find_element(By.TAG_NAME,'prefix2')
prefix2_shadow = shadow_root(prefix2)
prefix3 = prefix2.find_element(By.TAG_NAME,'prefix3')
prefix3_shadow = shadow_root(prefix3)
here = prefix3.find_element(By.CSS_SELECTOR,'prefix2')