본문으로 건너뛰기
SDETRole
SDETRole

학습 / 치트 시트

XPath·CSS 셀렉터 치트 시트

Selenium, Playwright, 브라우저 DevTools에서 쓰는 XPath와 CSS를 나란히 정리했습니다. CSS로 표현할 수 있다면 CSS를 쓰세요. 더 짧고 개발자에게도 익숙한 문법입니다. 화면에 보이는 텍스트로 찾거나 부모·조상 요소로 거슬러 올라가야 할 때는 XPath를 씁니다.

XPath 1.0 (브라우저 구현 기준), 최신 Chrome, Firefox, Safari가 지원하는 CSS Selectors Level 4 기준으로 검증

기본

목적XPathCSS
태그로 요소 찾기 (어디서든) //button button
id로 //*[@id='email'] #email
클래스로 (여러 클래스 중 하나) //*[contains(concat(' ', normalize-space(@class), ' '), ' active ')] .active
직계 자식 //ul/li ul > li
모든 하위 요소 //form//input form input
여러 셀렉터 (OR) //h1 | //h2 h1, h2
모든 요소 //* *

속성

목적XPathCSS
속성이 있음 //button[@disabled] button[disabled]
같음 //input[@name='q'] input[name='q']
포함 //a[contains(@href, 'orders')] a[href*='orders']
~로 시작 //a[starts-with(@href, 'https')] a[href^='https']
~로 끝남 //a[substring(@href, string-length(@href) - 3) = '.pdf'] a[href$='.pdf']
두 조건 모두 (AND) //input[@type='text' and @required] input[type='text'][required]
둘 중 하나 (OR) //input[@type='email' or @type='tel'] input[type='email'], input[type='tel']
부정 (NOT) //input[not(@disabled)] input:not([disabled])
테스트 ID //*[@data-testid='submit'] [data-testid='submit']

XPath 1.0에는 ends-with()가 없습니다. substring()을 쓰는 방식이 어디서나 동작하는 우회책입니다.

텍스트 (XPath 전용)

목적XPathCSS
텍스트 정확히 일치 (공백 정규화) //button[normalize-space()='Sign in'] 불가
텍스트 포함 //p[contains(., 'expired')] 불가
대소문자 무시하고 포함 //p[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'expired')] 불가
자기 자신의 텍스트 노드만 //label[text()='Email'] 불가

. (문자열 값)은 자식 요소의 텍스트까지 포함하지만, text()는 해당 요소 자신의 텍스트 노드만 매칭합니다. normalize-space()나 .을 우선 사용하세요.

관계와 축(axis)

목적XPathCSS
부모 //input[@id='email']/.. :has(> #email)
셀을 포함한 상위 행 //td[normalize-space()='#1043']/ancestor::tr tr:has(td[data-id='1043'])
바로 다음 형제 //label[.='Password']/following-sibling::input[1] label + input
뒤따르는 모든 형제 //h2/following-sibling::p h2 ~ p
바로 앞 형제 //button/preceding-sibling::input[1] 불가
레이블 셀 옆의 셀 //td[.='Diego Ramos']/following-sibling::td[1] 불가(텍스트에서 시작)
특정 자식을 포함한 요소 //li[.//button[@aria-label='Remove']] li:has(button[aria-label='Remove'])

:has()는 최신 Chrome, Edge, Safari, Firefox(121 이상)에서 동작합니다. 구형 브라우저와 일부 도구는 지원하지 않습니다.

위치

목적XPathCSS
첫 번째 자식 행 (1부터 시작) //tbody/tr[1] tbody tr:first-child
N번째 행 //tbody/tr[3] tbody tr:nth-child(3)
마지막 행 //tbody/tr[last()] tbody tr:last-child
끝에서 두 번째 //tbody/tr[last()-1] tbody tr:nth-last-child(2)
짝수 행 전부 //tbody/tr[position() mod 2 = 0] tbody tr:nth-child(even)
페이지 전체에서 첫 번째 일치 요소 (//button)[1] 불가: 도구의 first()를 사용합니다

//tr[1]은 "페이지의 첫 번째 tr"이 아니라 "부모 안에서 첫 번째인 모든 tr"을 뜻합니다. 페이지의 첫 번째 tr이 필요하면 (//tr)[1]을 쓰세요.

상태 가상 클래스 (CSS)

목적XPathCSS
체크된 체크박스 또는 라디오 //input[@checked] (initial state only) input:checked
비활성화됨 //button[@disabled] button:disabled
필수 입력 필드 //input[@required] input:required
빈 요소 //td[not(node())] td:empty

XPath는 HTML에 작성된 그대로의 속성을 읽기 때문에, 사용자가 체크박스를 체크해도 @checked는 바뀌지 않습니다. CSS의 :checked는 현재 상태를 반영합니다.

DevTools에서 직접 해 보기

작업코드
CSS, 일치하는 모든 요소 (Console) $$('tbody tr')
XPath, 일치하는 모든 요소 (Console) $x("//td[.='Mei Lin']")
Elements 패널에서 검색 Ctrl+F / Cmd+F, then type a selector or XPath
일치 개수 세기 $$('tbody tr').length

실습과 심화 학습

다른 치트 시트

SDETRole 전체에서 검색할 내용을 입력하세요.

Pagefind 전문 검색 · 브라우저에서 실행됩니다 검색 페이지 열기 →