Geonode logo
Geonode Team

Geonode Team

Atualizado: 7 de outubro de 2026

Publicado: 2 de setembro de 2026

XPath «preceding-sibling»: Como funciona (com exemplos)

`preceding-sibling` seleciona os nós que se encontram antes do nó de contexto, no mesmo nível da árvore. É bastante simples — até escreveres «`preceding-sibling::td[1]`» e obteres uma célula diferente daquela que esperavas. A razão é que «`preceding-sibling`» é um eixo inverso, e a numeração de posições num eixo inverso decorre de trás para a frente. Este guia aborda o que este método seleciona, a armadilha da numeração, em que difere de ``preceding`` e os padrões de extração que se destina a resolver.

O nosso interesse, dito de forma clara: somos a Geonode e vendemos proxies a quem faz scraping, pelo que o XPath está relacionado com o nosso negócio. Vale a pena referir que um seletor que não funciona nunca é um problema do proxy. Se a sua extração deixou de funcionar, o site alterou a sua marcação, e nem toda a largura de banda nem a rotação de endereços resolvem esse problema. Os dois são confundidos porque ambos se manifestam como «o meu scraper deixou de devolver dados» — mas uma falha no proxy produz respostas bloqueadas e páginas de erro, enquanto uma falha no seletor produz respostas bem-sucedidas que não devolvem nada. Verifique o HTML bruto antes de verificar qualquer outra coisa. Se a página estiver presente e o seu XPath devolver um conjunto de nós vazio, este artigo é relevante e o seu proxy está a funcionar corretamente.

O que «preceding-sibling» realmente seleciona

A especificação do XPath 1.0 define-o numa única linha: o eixo «preceding-sibling» «contém todos os irmãos anteriores do nó de contexto; se o nó de contexto for um nó de atributo ou um nó de espaço de nomes, o eixo «preceding-sibling» fica vazio».

Duas palavras transmitem o significado. Nós irmãos significa nós que partilham o mesmo pai — não primos, nem antepassados, nem nada que se encontre a uma profundidade diferente. Anteriores significa mais cedo na ordem do documento.

<div>
  <p>First</p>
  <p>Second</p>
  <span id="here">Context</span>
  <p>Third</p>
</div>

Com o span como nó de contexto:

preceding-sibling::p        → First, Second
following-sibling::p        → Third
preceding-sibling::*        → both p elements

Vale a pena recordar a ressalva relativa aos nós de atributo, pois explica uma classe de resultados vazios. Se tiver navegado até um atributo — //@class —, então preceding-sibling a partir daí estará vazio por definição, independentemente do que rodeia o elemento ao qual o atributo pertence. Os atributos não são irmãos de nada.

A armadilha do eixo inverso: «[1]

» não significa «primeiro» Esta é a principal fonte de resultados errados, e a especificação explica exatamente porquê.

O XPath classifica ancestor , ancestor-or-self , preceding e preceding-sibling como eixos inversos. Para os eixos inversos, a posição de proximidade é determinada ordenando os nós na ordem inversa do documento.

Assim, em preceding-sibling , a posição 1 é o irmão anterior mais próximo — aquele imediatamente antes do nó de contexto — e não o primeiro no documento.

<div>
  <p>Alpha</p>
  <p>Beta</p>
  <p>Gamma</p>
  <span id="here">Context</span>
</div>
preceding-sibling::p[1]     → Gamma   (nearest)
preceding-sibling::p[2]     → Beta
preceding-sibling::p[3]     → Alpha   (furthest)
(preceding-sibling::p)[1]   → Alpha   (first in document order)

Os parênteses mudam tudo. Sem eles, [1] é um predicado aplicado ao longo do eixo inverso e significa «mais próximo». Com elas, o resultado do eixo é primeiro recolhido num conjunto de nós pela ordem do documento e [1] indexa nesse conjunto, significando «primeiro».

Compare com following-sibling , que é um eixo para a frente onde os dois coincidem:

following-sibling::p[1]     → the next one
(following-sibling::p)[1]   → also the next one

Essa assimetria é a razão pela qual as pessoas que aprenderam com following-sibling se deixam enganar por preceding-sibling . O hábito transfere-se, mas a semântica não.

Na prática, a forma sem parênteses é quase sempre a que se pretende. «A etiqueta imediatamente antes deste valor» é o requisito habitual, e isso é preceding-sibling::label[1] . Recorra aos parênteses apenas quando pretender genuinamente «a primeira no documento», o que é uma necessidade mais rara do que parece.

«preceding-sibling» versus «preceding»

Dois eixos diferentes com nomes muito semelhantes, o que pode causar confusão, mas a diferença é importante.

A especificação define «preceding» como contendo «todos os nós no mesmo documento que o nó de contexto que se encontram antes do nó de contexto na ordem do documento, excluindo quaisquer antepassados e excluindo nós de atributos e nós de espaço de nomes».

Portanto, «preceding» é tudo o que se encontra anteriormente no documento, a qualquer profundidade, excluindo os antepassados. «preceding-sibling» são apenas aqueles que partilham o mesmo pai.

<body>
  <header><h1>Title</h1></header>
  <div>
    <p>One</p>
    <span id="here">Context</span>
  </div>
</body>

Extraído do «span»:

preceding-sibling::*    → the p only
preceding::*            → the p, the h1, and the header

A exclusão dos antepassados é a parte que surpreende as pessoas. O «div» que contém o «span» não está em preceding, apesar de a sua tag de abertura aparecer anteriormente na fonte. Os antepassados são excluídos por definição, porque o eixo diz respeito ao que veio antes de si, e não ao que o contém.

Quando utilizar cada um. preceding-sibling para relações estruturadas — um rótulo e o seu valor, um título e o parágrafo abaixo, células numa linha. preceding para relações genuinamente flexíveis, tais como «o título mais próximo em qualquer ponto acima deste elemento, independentemente do aninhamento». preceding é mais abrangente, consideravelmente mais lento e muito mais suscetível de corresponder a algo que não pretendia.

O Padrão «Rótulo-Valor»

É por isso que o padrão «preceding-sibling

» existe no trabalho de scraping, e vale a pena dominá-lo adequadamente, pois a maior parte das marcações reais é uma variante deste padrão.

O problema: pretende-se um valor que só seja identificável pelo rótulo que se encontra ao seu lado. O valor em si não tem nenhuma classe útil, nenhum id, nada que o distinga.

Listas de definição:

<dl>
  <dt>Price</dt>
  <dd>£42.00</dd>
  <dt>Stock</dt>
  <dd>In stock</dd>
</dl>

Selecionar o preço significa encontrar o dd

cujo dt

imediatamente anterior diga «Price»:

//dd[preceding-sibling::dt[1] = 'Price']

Leia isto de dentro para fora: para cada dd

, considere o seu dt

imediatamente anterior; retenha o dd

se esse texto for «Price». Note-se que o [1]

é essencial. Sem ele, preceding-sibling::dt = 'Price'

é verdadeiro se qualquer dt

anterior corresponder, pelo que o segundo dd

também se qualificaria. Trata-se de um erro real e frequente.

Células da tabela:

<tr>
  <td>SKU</td>
  <td>ABC-123</td>
</tr>
//td[preceding-sibling::td[1] = 'SKU']

Ou a partir da coluna do cabeçalho ao longo de uma linha de uma tabela de especificações com duas colunas:

//th[normalize-space() = 'Weight']/following-sibling::td[1]

Esta segunda forma é normalmente preferível quando o rótulo é um «th

», porque se lê da esquerda para a direita e corresponde à forma como a tabela está estruturada.

Melhorias de robustez que permitem que estas expressões resistam a marcação real:

//dd[preceding-sibling::dt[1][normalize-space() = 'Price']]

normalize-space()

elimina os espaços em branco internos e apara as extremidades, o que lida com o HTML «pretty-printed» que, de outra forma, iria comprometer uma comparação exata de cadeias de caracteres. É a função de maior valor no scraping com XPath.

Para correspondências parciais, contains()

é mais flexível e, consequentemente, menos preciso:

//dd[preceding-sibling::dt[1][contains(., 'Price')]]

Tenha cuidado: contains(., 'Price')

também corresponde a «Preço sem IVA» e «Preço histórico». Se a página tiver vários rótulos deste tipo, obterá vários resultados e o seu código irá selecionar o primeiro silenciosamente.

Títulos e conteúdo subsequente, que é o mesmo padrão na direção oposta:

//h2[normalize-space() = 'Specifications']/following-sibling::table[1]

A primeira tabela após esse título. Este é um requisito verdadeiramente comum em páginas de documentação e de produtos, e não existe nenhum equivalente em CSS que expresse «a primeira tabela após este título específico».

Combinação com predicados e condições O

preceding-sibling

integra-se com o resto do XPath, e vale a pena conhecer algumas combinações.

Contagem de elementos irmãos — útil para encontrar o primeiro ou o último item, ou para verificar a posição:

//li[count(preceding-sibling::li) = 0]     first li
//li[count(preceding-sibling::li) < 3]     first three

Verificar a existência — um conjunto de nós num contexto booleano é verdadeiro quando não está vazio:

//p[preceding-sibling::h2]                 paragraphs with an h2 somewhere before
//p[not(preceding-sibling::p)]             first paragraph among its siblings

Encadeamento de eixos:

//span[@class='value']/preceding-sibling::*[1]/text()

O elemento imediatamente anterior, independentemente da tag, e o seu texto.

Condições múltiplas:

//td[preceding-sibling::td[1] = 'Status'][normalize-space() != '']

Dois predicados aplicados em sequência: a célula a seguir a um rótulo «Status» e que não esteja vazia.

Uma nota sobre o atalho ..

, que é frequentemente mais claro do que um eixo:

//dt[.='Price']/following-sibling::dd[1]

é normalmente mais legível do que a forma preceding-sibling

para o mesmo resultado, e segue a direção em que o documento está escrito. Prefira-o quando a âncora for o rótulo.

Onde os seletores CSS podem e não podem substituí-lo

A ideia generalizada de que «o CSS não consegue olhar para trás» precisa de ser atualizada.

O CSS já permite definir condições de irmãos com :has(). Amplamente suportado nos navegadores modernos, permite que um seletor seja condicional a uma relação de irmãos:

dt:has(+ dd)          a dt immediately followed by a dd
li:has(~ li.active)   an li with a later sibling that is active

O que o CSS ainda não consegue fazer:

Selecionar por conteúdo de texto. Não existe um equivalente em CSS para [text() = 'Price']. Só por isso, o padrão «rótulo-valor» continua a ser domínio do XPath, porque a correspondência de rótulos é uma correspondência de texto.

Navegar até um antepassado arbitrário. :has() fornece uma forma de seleção de pais, mas não existe um eixo geral de antepassados.

Indexar ao longo de um eixo inverso. Não existe nenhuma construção CSS que signifique «o elemento anterior mais próximo deste tipo».

E o que o CSS faz melhor: tudo o que é simples. Seleção por classe e id, relações de descendência, correspondência de atributos. Os seletores CSS são mais legíveis, têm melhor suporte por parte das ferramentas e são mais rápidos na maioria dos motores.

A política sensata é utilizar CSS por predefinição e recorrer ao XPath apenas nos casos específicos em que for necessária a correspondência de texto ou a navegação para trás. Misturá-los numa única base de código é aceitável, e um scraper que utilize CSS em 90% dos seus seletores e XPath nos 10% mais complexos é mais fácil de manter do que um que se limite a apenas um dos dois.

Desempenho e Fragilidade

Duas limitações práticas.

Desempenho. A função preceding-sibling é limitada pelo número de nós irmãos, que normalmente é pequeno — o que não constitui problema. A função preceding analisa tudo o que se encontra antes do nó de contexto no documento, o que, numa página grande, é dispendioso em termos de recursos e, dentro de um ciclo, tem um custo quadrático. Se um seletor que utiliza preceding for lento, essa é quase certamente a razão. A solução habitual consiste em reescrevê-lo utilizando preceding-sibling a partir de um nó de contexto mais próximo.

Fragilidade. Os seletores baseados em irmãos dependem da estrutura do documento, que é exatamente o que uma reformulação altera. preceding-sibling::td[1] deixa de funcionar silenciosamente no dia em que alguém insere uma coluna. Não há erro; o seletor corresponde a uma célula diferente e os seus dados estão discretamente errados.

Três medidas de mitigação que realmente ajudam:

Ancore no texto em vez de na posição, sempre que possível. //dt[.='Price']/following-sibling::dd[1] sobrevive a uma reordenação da lista. (//dd)[3] não.

Verifique o que extrai. Se um preço tiver de corresponder a um padrão de moeda, verifique-o. Um seletor que comece a devolver o estado das ações em vez do preço fica invisível, a menos que algo valide o formato.

Dê preferência a dados estruturados incorporados, quando existirem. Se a página contiver JSON-LD num bloco <script type="application/ld+json">, analise-o em vez disso. Foi concebido para ser lido por máquinas, é muito mais estável ao longo de reformulações e elimina toda a fragilidade dos seletores. Vale a pena dedicar trinta segundos a verificar isso antes de escrever qualquer XPath.

As falhas estruturais silenciosas pertencem à mesma classe de problemas que descrevemos em por que é importante testar proxies — o pedido é bem-sucedido, a análise é bem-sucedida e os dados estão errados.

Quando não o utilizar

Quando o elemento tiver um identificador utilizável. Se houver um id, uma classe ou um atributo data, utilize-o. Um seletor que depende da estrutura é, sem dúvida, mais frágil do que aquele que depende de um nome escolhido deliberadamente pelo programador.

Quando houver dados estruturados disponíveis. JSON-LD, microdados, uma carga JSON por trás de um XHR. Qualquer uma destas opções é preferível à análise de HTML renderizado.

Quando a relação for genuinamente flexível. Se te vires a escrever preceding::*[5], a estrutura não te está realmente a dizer nada e o seletor irá deixar de funcionar na próxima implementação. Reconsidera a abordagem.

Quando o CSS é suficiente. Para seleções simples, o CSS é mais legível e tem melhor suporte. Reserve o XPath para correspondência de texto e navegação para trás.

Quando depende de funcionalidades do XPath 2.0 num navegador. Os navegadores implementam o XPath 1.0 através de document.evaluate, e o Selenium segue o navegador. Portanto, nada de matches(), nada de expressões regulares, nada de upper-case() nem de tipos de sequência. As bibliotecas do lado do servidor, como o lxml, também seguem o XPath 1.0 para a API comum. Se um trecho de código que encontrou online não funcionar, verifique se utiliza uma função que só existe numa versão posterior.

Perguntas frequentes

O que significa «preceding-sibling» no XPath?

Seleciona todos os nós que partilham o mesmo pai que o nó de contexto e que aparecem antes deste na ordem do documento. Não inclui antepassados, descendentes nem nós noutros níveis da árvore — apenas irmãos. Fica vazio se o nó de contexto for um atributo ou um nó de espaço de nomes.

Por que razão «preceding-sibling»[1] devolve o elemento errado?

Porque «preceding-sibling» é um eixo inverso, e a numeração de posições em eixos inversos segue a ordem inversa do documento. «[1]», portanto, significa o irmão anterior mais próximo, não o primeiro no documento. Para obter o primeiro na ordem do documento, coloque o eixo entre parênteses: «(preceding-sibling::p)[1]».

Qual é a diferença entre «preceding» e «preceding-sibling»? «

preceding-sibling» abrange apenas nós com o mesmo pai. «preceding» abrange todos os nós anteriores no documento, a qualquer profundidade, excluindo antepassados e nós de atributos. «preceding» é muito mais abrangente, consideravelmente mais lento e muito mais suscetível de corresponder a algo indesejado.

Como seleciono um valor com base no seu rótulo em XPath?

Procure o rótulo pelo texto e, em seguida, selecione o elemento adjacente: //dt[normalize-space()='Price']/following-sibling::dd[1], ou a partir do valor, //dd[preceding-sibling::dt[1]='Price']. O [1] é importante — sem ele, o predicado é verdadeiro se qualquer rótulo precedente corresponder.

Os seletores CSS conseguem fazer o que o «preceding-sibling» faz?

Em parte. O seletor «:has()» permite a seleção condicional de irmãos em navegadores modernos. O que o CSS ainda não consegue fazer é selecionar por conteúdo de texto ou por índice ao longo de um eixo inverso, e a correspondência de texto é precisamente o que o padrão «label-value» requer. Utilize CSS para seleções simples e XPath quando precisar de texto ou de navegação inversa.

O «preceding-sibling» funciona no Selenium e nos navegadores?

Sim. Os navegadores implementam o XPath 1.0 através de document.evaluate, e o Selenium utiliza o motor do navegador. O eixo é o XPath 1.0 e está universalmente disponível. O que não está disponível é qualquer funcionalidade do XPath 2.0 ou posterior — nem expressões regulares, nem «matches()», nem «upper-case()».

O «preceding-sibling» é lento?

Normalmente não. O desempenho é limitado pelo número de irmãos, que costuma ser pequeno. O eixo «preceding» é o mais lento, porque analisa tudo o que vem antes no documento, e dentro de um ciclo que se torna quadrático. Se um seletor baseado em irmãos for lento, verifique se utilizou realmente «preceding».

Como posso tornar os seletores XPath menos frágeis?

Sempre que possível, baseie-se no texto em vez da posição, utilize normalize-space() para contornar diferenças de espaços em branco, dê preferência a identificadores e atributos de dados em vez da estrutura, verifique se existe JSON-LD incorporado antes de analisar o HTML e valide a forma do que extrai, para que um seletor que corresponda ao elemento errado falhe de forma evidente, em vez de silenciosamente.

Conclusão: `

`preceding-siblingé uma ferramenta específica com uma única função: percorrer os nós para trás, entre nós do mesmo nível. O que é importante ter em conta é que se trata de um eixo inverso, pelo que[1]`` significa «o mais próximo» em vez de «o primeiro», e a adição de parênteses inverte completamente esse significado. Essa única distinção é responsável pela maioria dos resultados errados que as pessoas obtêm com esta função.

O seu verdadeiro valor reside no padrão «rótulo-valor» — extrair um campo que só é identificável pelo texto que se encontra ao seu lado. O CSS colmatou parte dessa lacuna com :has(), mas ainda não consegue selecionar com base no conteúdo do texto, e o texto é exatamente o que um rótulo é. É nesse caso que o XPath continua a ser a ferramenta certa, em vez de ser apenas a mais habitual.

É importante ter em conta que os seletores estruturais falham silenciosamente. Uma nova coluna, uma lista reordenada, um div envolvente, e o seu seletor passa a corresponder a outra coisa, enquanto tudo continua a parecer estar bem. Baseie-se no texto sempre que possível, verifique se existem dados estruturados incorporados antes de escrever qualquer seletor e valide o resultado — porque a falha que consegue ver nunca é a mais dispendiosa.