DOM이란? HTML과 DOM의 차이를 그림으로 이해하기
DOM(Document Object Model)이 무엇인지, HTML과 무엇이 다른지 그림과 실습으로 설명합니다. 브라우저가 HTML을 DOM 트리로 바꾸는 과정, 부모·자식 요소, 개발자 도구에서 DOM을 보는 법까지 다룹니다.
DOM(Document Object Model)은 HTML 문서의 태그를 부모와 자식으로 이어 만든 트리입니다. 브라우저는 이 트리를 보고 화면을 그리고, JavaScript와 크롤러는 이 트리에서 원하는 요소를 찾아 값을 읽거나 바꿉니다.
HTML은 서버가 보낸 글자이고, DOM은 그 글자를 읽어 만든 트리입니다.
이 글에서는 DOM이 무엇인지, HTML과 무엇이 다른지, 브라우저가 HTML을 어떻게 DOM으로 바꾸는지 차례로 살펴봅니다. 마지막에는 개발자 도구에서 DOM을 직접 확인하는 방법과, 페이지 소스 보기와 검사 화면의 내용이 다른 이유를 다룹니다.
DOM이란 무엇인가요?
아래는 책방 페이지의 HTML 일부입니다.
<body>
<article>
<h3>책 제목</h3>
<p class="price">12,000원</p>
</article>
</body>서버가 이 HTML을 보내면 브라우저가 받는 것은 <body><article><h3>책 제목</h3>...처럼 이어진 긴 문자열 하나입니다. 문자열 상태로는 "두 번째 책의 가격"이 어디에 있는지 바로 찾을 수 없습니다.
그래서 브라우저는 문자열을 읽으면서 태그끼리의 관계를 트리로 정리합니다. 다른 태그를 감싸는 태그는 부모, 감싸인 태그는 자식이 됩니다. 위 HTML에서는 body 아래에 article이 있고, article 아래에 h3와 p가 있습니다. 이렇게 만든 트리가 DOM이고, 트리의 한 칸 한 칸을 요소(Element) 라고 부릅니다.
이름을 나눠 보면 뜻이 더 분명해집니다.
- Document: 웹페이지 문서 한 장
- Object: 문서 안의 요소 하나하나를 프로그램이 다룰 수 있는 객체로 만든다는 뜻
- Model: 그 요소들이 어떻게 이어져 있는지 나타낸 구조
즉 DOM은 웹페이지를 프로그램이 다룰 수 있는 형태로 바꿔 놓은 것입니다. JavaScript의 document.querySelector()나 파이썬 크롤러의 soup.select()는 모두 이 트리에서 요소를 찾습니다.
HTML과 DOM은 무엇이 다른가요?
둘은 같은 내용을 담고 있어서 자주 섞어 부르지만, 정체가 다릅니다.
| HTML | DOM | |
|---|---|---|
| 정체 | 글자로 쓴 문서 | 그 문서를 읽어 메모리에 만든 트리 |
| 만드는 쪽 | 개발자가 쓰고 서버가 보낸다 | 브라우저(또는 파서)가 만든다 |
| 바뀌는 때 | 받은 뒤로는 그대로다 | JavaScript가 고치면 바로 바뀐다 |
| 확인하는 곳 | 페이지 소스 보기 | 개발자 도구의 Elements 패널 |
차이가 드러나는 대표적인 예가 표(table)입니다. HTML에 tbody 없이 표를 써도, 브라우저는 DOM을 만들 때 tbody를 알아서 넣습니다.
<!-- 서버가 보낸 HTML -->
<table><tr><td>1</td></tr></table>
<!-- 브라우저가 만든 DOM -->
<table><tbody><tr><td>1</td></tr></tbody></table>크롤러를 만들 때 이 차이로 자주 막힙니다. 개발자 도구에서 본 대로 table tbody tr이라는 선택자를 쓰면, 파이썬 BeautifulSoup의 기본 파서(html.parser)는 tbody를 넣지 않기 때문에 아무것도 찾지 못합니다. 이때는 table tr로 고르면 됩니다.
브라우저는 HTML을 어떻게 DOM으로 바꾸나요?
HTML 문자열을 읽어 트리로 바꾸는 일을 파싱(Parsing) 이라고 합니다. 파싱의 규칙은 두 가지입니다.
- 여는 태그를 만나면 지금 부모 아래에 자식으로 붙이고, 그 자식이 새 부모가 됩니다.
- 닫는 태그를 만나면 부모가 한 단계 위로 돌아갑니다.
아래에서 다음을 눌러 HTML을 한 줄씩 읽어 보세요. 점선 테두리가 지금 부모입니다.
HTML을 들여쓰기해서 쓰는 이유도 여기에 있습니다. 들여쓰기 깊이가 DOM 트리의 깊이와 같아서, 어느 태그가 어느 태그의 자식인지 눈으로 구분하기 쉽습니다. 다만 브라우저는 들여쓰기가 아니라 여는 태그와 닫는 태그의 짝을 보고 트리를 만듭니다.
부모, 자식, 형제 요소는 무엇인가요?
DOM에서 요소끼리의 관계는 가족 관계 이름으로 부릅니다. 앞의 HTML을 기준으로 정리하면 다음과 같습니다.
| 관계 | 뜻 | 예 |
|---|---|---|
| 부모 (parent) | 바로 위에서 감싸는 요소 | h3의 부모는 article |
| 자식 (child) | 바로 아래에 있는 요소 | article의 자식은 h3, p |
| 형제 (sibling) | 부모가 같은 요소 | h3와 p는 형제 |
| 조상 (ancestor) | 위쪽으로 이어진 모든 요소 | h3의 조상은 article, body |
| 자손 (descendant) | 아래쪽으로 이어진 모든 요소 | body의 자손은 article, h3, p |
이 관계는 요소를 고를 때 그대로 쓰입니다. CSS 선택자 article h3는 "article의 자손인 h3"라는 뜻이고, article > h3는 "article의 바로 아래 자식인 h3"라는 뜻입니다. 선택자는 CSS 선택자란? 글에서 자세히 다룹니다.
개발자 도구에서 DOM 보는 법
지금 보고 있는 페이지의 DOM은 브라우저의 개발자 도구에서 바로 볼 수 있습니다. 크롬 기준입니다.
- 페이지에서 확인하고 싶은 글자에 마우스를 올리고 오른쪽 버튼을 눌러
검사를 고릅니다.F12(Mac은Cmd + Option + I)를 눌러도 열립니다. Elements패널에 DOM 트리가 나오고, 방금 고른 요소가 강조되어 있습니다.- 줄 앞의 삼각형을 눌러 접고 펴면서 부모와 자식 관계를 따라가 봅니다.
Elements 패널에서 글자를 고치거나 요소를 지우면 화면도 바로 바뀝니다. 이건 내 브라우저에 있는 DOM만 바꾼 것이라, 새로고침하면 서버가 보낸 HTML로 다시 만들어집니다.
페이지 소스 보기와 검사 화면은 왜 다를까요?
오른쪽 버튼 메뉴의 페이지 소스 보기(Ctrl + U, Mac은 Cmd + Option + U)와 검사는 비슷해 보이지만 보여 주는 것이 다릅니다.
- 페이지 소스 보기: 서버가 처음 보낸 HTML
- 검사(Elements): 그 HTML로 만든 DOM에, 페이지가 열린 뒤 JavaScript가 고친 내용까지 반영된 지금의 DOM
요즘 웹페이지는 HTML을 받은 뒤에 JavaScript가 데이터를 따로 불러와 DOM에 넣는 경우가 많습니다. 이런 페이지에서는 검사 화면에는 있는 글자가 페이지 소스에는 없습니다.
크롤러에게 중요한 것은 앞쪽입니다. 파이썬의 requests는 서버가 보낸 HTML만 받고 JavaScript는 실행하지 않습니다. 그래서 크롤러가 읽을 수 있는지는 검사 화면이 아니라 페이지 소스 보기로 확인해야 합니다. 페이지 소스에서 Ctrl + F로 원하는 글자를 찾아보고, 없다면 JavaScript가 나중에 넣은 데이터입니다.
정리
- DOM은 HTML의 태그를 부모와 자식으로 이은 트리이고, 트리의 한 칸을 요소라고 부릅니다.
- HTML은 서버가 보낸 글자이고, DOM은 그 글자를 파싱해 만든 트리입니다. 브라우저가
tbody를 넣거나 JavaScript가 내용을 고치면 둘이 달라집니다. - 지금의 DOM은 개발자 도구의 Elements 패널에서, 서버가 보낸 HTML은 페이지 소스 보기에서 확인합니다.
- 크롤러는 서버가 보낸 HTML로 DOM을 만들기 때문에, 크롤링할 수 있는지는 페이지 소스 보기로 확인합니다.
DOM에서 원하는 요소를 정확히 고르는 문법이 CSS 선택자입니다. 다음 글 CSS 선택자란? 크롤링에서 원하는 요소만 고르는 법에서 이어집니다. 크롤러가 DOM과 선택자를 함께 쓰는 과정을 직접 눌러 보며 따라가고 싶다면 크롤러는 어떻게 원하는 글자만 골라낼까? 강의를 열어 보세요.