HTML(과 XML)에서 특정 요소를 찾을 때 CSS 선택자만으로 부족한 경우 XPath (XML Path Language)를 쓰곤 합니다.
XPath는 HTML/XML 문서를 트리 형태로 보고 노드를 경로로 지정해 선택하는 언어입니다.
기본 경로 표현부터 텍스트 포함 검색까지 가능합니다.
XPath 기본 구조
기본적으로 문서 구조를 따라 선택자를 씁니다. 기본적인 표현은 이렇습니다:
/bookstore/book/title
중간 생략시 사이에 //를 씁니다.
/bookstore//title
/: 루트부터 내려가는 절대 경로//: 문서 어디서든 해당 요소를 찾는 전체 경로@속성명: 속성 선택*: 모든 노드(태그)[조건]: 조건 필터
//book[@lang="en"]
→ lang="en" 속성을 가진 모든 book 요소 선택.
인덱스 지정과 위치
개별 노드를 직접 선택할 수도 있습니다(인덱스는 1부터 시작합니다).
(//div[@class="post"])[1]
→ class="post"인 <div> 중 첫 번째 요소를 선택합니다.
텍스트가 정확히 일치하는 노드 선택
완전한 일치 텍스트 검색은 다음처럼 씁니다:
//h1[text()="Hello World"]
정확히 "Hello World"라는 텍스트를 가진 <h1> 요소를 모두 선택합니다.
텍스트가 부분 포함된 노드를 선택하려면
특정 문자열을 포함한 노드를 찾을 때는 contains() 함수를 사용합니다.
방법 1 — . (전체 문자열) 사용
//button[contains(., "로그인하기")]
- 버튼 노드(
//button) 중에서 - 자신 안의 전체 텍스트(자식 포함)에
"로그인"이 들어간 요소를 찾습니다.
이 방법은 문서 전체 텍스트를 하나의 문자열로 본 후 검색합니다. 그래서 텍스트가 여러 노드로 쪼개진 경우에도 부모 요소를 기준으로 찾아냅니다.
예컨대 아래처럼 로그인과 하기가 각각 다른 노드에 있어도 검색해낸다는 장점이 있습니다.
<button><b>로그인</b>하기</button>
만약 아래처럼 *를 쓰면 최상위 요소인 html 요소부터 찾아들어갑니다.
//*[contains(., "로그인하기")]
직접 해보는 방법도 있습니다. 브라우저 개발자 도구 JS 콘솔에서 아래 명령을 쳐 보시면 됩니다($x는 브라우저 콘솔에서만 작동합니다).
$x('//*[contains(., "다")]')
contains()는 contains(string, string) → boolean 형태의 XPath 함수입니다. 첫 번째 인자는 문자열로 자동 변환되는데, .처럼 노드를 가리키는 표현식도 사용할 수 있습니다.
.은 현재 노드를 의미하고, 문자열이 필요한 자리에 노드가 들어오면 해당 노드의 문자열 값이 사용됩니다. 이 값은 현재 노드와 그 하위 노드에 포함된 모든 텍스트를 하나로 합친 문자열입니다(개념적으로 DOM의 textContent에 가깝습니다).
따라서 contains(., "...") 형태로 사용하면, 현재 노드 전체에 포함된 텍스트 중에 ...이 들어 있는지를 검사하게 됩니다.
방법 2 — text()와 contains() 함께 쓰기
//*[text()[contains(., "로그인")]]
이 표현은 다음과 같습니다:
text()– 텍스트 노드를 일일이 검사[contains(., "로그인")]– 텍스트 노드 중 하나라도"로그인"을 포함하면 해당 부모 요소를 선택
즉 "로그인"이라는 문자열이 포함된 텍스트 노드를 가진 요소만 고르게 됩니다.
주의: contains vs contains(text())
contains(. , "문자열")과 contains(text(), "문자열")은 비슷해 보이지만 의미가 다릅니다.
첫 번째는 전체 자식 텍스트를 하나의 문자열로 합친 결과에서 검사하고, 두 번째는 각 텍스트 노드별로 contains()를 적용합니다.
실전에서 보통 찾고 싶은 것은 문자열이 포함된 요소 전체이므로 contains(., "문자열")이나 text()[contains(., "문자열")]를 많이 씁니다.
예시
다음과 같은 HTML 구조가 있다고 해봅시다:
<li><a>로그인하기</a></li>
<li><a>지금 로그인</a></li>
<li><a>회원가입</a></li>
//a[text()="로그인하기"]
→ 텍스트가 정확히로그인하기인<a>요소만 선택
→ 결과: 첫 번째 요소만 선택//a[contains(text(), "로그인")]
→ 텍스트에로그인이 포함된<a>요소 선택
→ 결과: 첫 번째 / 두 번째 요소 모두 선택//*[@class="login" and contains(., "로그인")]
→class="login"속성을 가지면서
→ 텍스트(자식 노드 포함)에로그인이 포함된 요소 선택
→ 결과: 텍스트 + class 조건을 모두 만족하는 요소만 선택
속성에 대한 텍스트 포함 검색
속성 텍스트 안에서도 부분 검색이 가능합니다:
//input[contains(@placeholder, "이메일")]
→ placeholder 속성에 "이메일"이 포함된 input 요소 선택.
고급 팁 — 대소문자 무시 매칭
원래 contains()는 대소문자 구분합니다. 대소문자 구분 없이 찾으려면 translate(), normalize-space() 등을 조합할 수 있습니다.
정리
//tag[text()="..."]
→ 텍스트가 정확히 일치하는 요소 선택//tag[contains(text(), "...")]
→ 텍스트에 특정 문자열이 부분 포함된 요소 선택//*[contains(., "...")]
→ 자신과 자식 노드를 포함한 전체 텍스트에 문자열이 포함된 요소 선택//@attr="value"
→ 속성값이 정확히 일치하는 속성 선택//*[contains(@attr, "part")]
→ 속성값에 특정 문자열이 부분 포함된 요소 선택
XPath는 한 번 익히면 광범위한 노드 선택 + 텍스트 기반 검색이 가능해서 유용합니다.










댓글 남기기