Aprender / Cheat sheet
Cheat sheet de XPath e seletores CSS
XPath e CSS lado a lado, para Selenium, Playwright e DevTools do navegador. Use CSS quando ele consegue expressar o que você precisa, já que é mais curto e é a sintaxe que os desenvolvedores conhecem. Recorra ao XPath quando precisar encontrar um texto visível ou subir na árvore até um pai ou ancestral.
Conferido com XPath 1.0 (o que os navegadores implementam), CSS Selectors Level 4 como suportado nas versões atuais de Chrome, Firefox e Safari
Básico
| Objetivo | XPath | CSS |
|---|---|---|
| Elemento por tag (em qualquer lugar) | //button | button |
| Por id | //*[@id='email'] | #email |
| Por classe (uma entre várias) | //*[contains(concat(' ', normalize-space(@class), ' '), ' active ')] | .active |
| Filho direto | //ul/li | ul > li |
| Qualquer descendente | //form//input | form input |
| Vários seletores (OU) | //h1 | //h2 | h1, h2 |
| Qualquer elemento | //* | * |
Atributos
| Objetivo | XPath | CSS |
|---|---|---|
| Tem o atributo | //button[@disabled] | button[disabled] |
| Igual a | //input[@name='q'] | input[name='q'] |
| Contém | //a[contains(@href, 'orders')] | a[href*='orders'] |
| Começa com | //a[starts-with(@href, 'https')] | a[href^='https'] |
| Termina com | //a[substring(@href, string-length(@href) - 3) = '.pdf'] | a[href$='.pdf'] |
| Duas condições (E) | //input[@type='text' and @required] | input[type='text'][required] |
| Uma ou outra condição (OU) | //input[@type='email' or @type='tel'] | input[type='email'], input[type='tel'] |
| Negação | //input[not(@disabled)] | input:not([disabled]) |
| Test id | //*[@data-testid='submit'] | [data-testid='submit'] |
O XPath 1.0 não tem ends-with(): a forma com substring() é a alternativa portável.
Texto (só XPath)
| Objetivo | XPath | CSS |
|---|---|---|
| Texto exato, com espaços normalizados | //button[normalize-space()='Sign in'] | não é possível |
| Texto contém | //p[contains(., 'expired')] | não é possível |
| Contém, sem diferenciar maiúsculas | //p[contains(translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'), 'expired')] | não é possível |
| Só o próprio nó de texto | //label[text()='Email'] | não é possível |
. (o valor de string) inclui o texto dos elementos filhos; text() só encontra os nós de texto do próprio elemento. Prefira normalize-space() ou .
Relações e eixos
| Objetivo | XPath | CSS |
|---|---|---|
| Pai | //input[@id='email']/.. | :has(> #email) |
| Linha ancestral de uma célula | //td[normalize-space()='#1043']/ancestor::tr | tr:has(td[data-id='1043']) |
| Próximo irmão | //label[.='Password']/following-sibling::input[1] | label + input |
| Todos os irmãos seguintes | //h2/following-sibling::p | h2 ~ p |
| Irmão anterior | //button/preceding-sibling::input[1] | não é possível |
| Célula ao lado de uma célula de rótulo | //td[.='Diego Ramos']/following-sibling::td[1] | não é possível (parte do texto) |
| Elemento que contém um filho | //li[.//button[@aria-label='Remove']] | li:has(button[aria-label='Remove']) |
:has() funciona nas versões atuais de Chrome, Edge, Safari e Firefox (121+). Navegadores mais antigos e algumas ferramentas o rejeitam.
Posição
| Objetivo | XPath | CSS |
|---|---|---|
| Primeira linha filha (base 1) | //tbody/tr[1] | tbody tr:first-child |
| Enésima linha | //tbody/tr[3] | tbody tr:nth-child(3) |
| Última linha | //tbody/tr[last()] | tbody tr:last-child |
| Penúltima | //tbody/tr[last()-1] | tbody tr:nth-last-child(2) |
| Todas as linhas pares | //tbody/tr[position() mod 2 = 0] | tbody tr:nth-child(even) |
| Primeiro resultado na página inteira | (//button)[1] | não é possível: use o first() da sua ferramenta |
//tr[1] significa "todo tr que é o primeiro tr do seu pai", e não "o primeiro tr da página". Para isso, use (//tr)[1].
Pseudo-classes de estado (CSS)
| Objetivo | XPath | CSS |
|---|---|---|
| Checkbox ou radio marcado | //input[@checked] (initial state only) | input:checked |
| Desabilitado | //button[@disabled] | button:disabled |
| Campo obrigatório | //input[@required] | input:required |
| Elemento vazio | //td[not(node())] | td:empty |
O XPath lê os atributos como estão escritos no HTML, então @checked não muda quando o usuário marca a caixa. O :checked do CSS acompanha o estado real.
Teste no DevTools
| Tarefa | Código |
|---|---|
| CSS, todos os resultados (Console) | $$('tbody tr') |
| XPath, todos os resultados (Console) | $x("//td[.='Mei Lin']") |
| Buscar no painel Elements | Ctrl+F / Cmd+F, then type a selector or XPath |
| Contar resultados | $$('tbody tr').length |