XPath
Introdução
- O XPath significa XML Path Language.
- É uma linguagem de consulta que permite navegar por documentos que possuem marcações como o HTML (HyperText Markup Language).
Exemplos
- Exemplo: Verifica quantos nós existem na página e informa a quantidade por tipo de nó. O programa usa um dicionário para armazenar as tags encontradas (chave) e a quantidade de cada tag (valor).
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By opcoes = webdriver.ChromeOptions() opcoes.headless = True driver = webdriver.Chrome(options=opcoes) driver.get('https://www.python.org') nos = driver.find_elements(By.XPATH, '//*') print("Número de nós: " + str(len(nos))) tags={} for no in nos: valor = tags.setdefault(no.tag_name, 0) + 1 chave = str(no.tag_name) if chave in tags: valor = tags[chave] + 1 tags[chave] = valor else: tags[chave] = 1 print("Número de diferentes tags =", len(tags)) for x, y in tags.items(): print(x, ":", y) driver.quit()
A resposta do programa é mostrada abaixo.
Número de nós: 691 Número de diferentes tags = 38 html : 1 head : 1 meta : 24 link : 16 script : 12 title : 1 body : 1 div : 49 p : 23 strong : 3 nav : 2 a : 217 span : 72 ul : 30 li : 171 header : 1 h1 : 6 img : 1 form : 1 fieldset : 1 label : 1 input : 1 button : 1 small : 2 pre : 5 code : 14 ol : 1 section : 1 h2 : 10 time : 10 blockquote : 1 table : 1 tbody : 1 tr : 1 td : 1 em : 1 b : 5 footer : 1
- Exemplo: Localiza todas as âncoras (anchor) da página oficial do Python. Em seguida, mostra o valor de href (se existir) e o texto que aparece na âncora (se existir).
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By opcoes = webdriver.ChromeOptions() opcoes.headless = True driver = webdriver.Chrome(options=opcoes) driver.get('https://www.python.org') links = driver.find_elements(By.XPATH, '//a') print("Número de links: " + str(len(links)) + "\n") for link in links: print(link.get_attribute('href')) print(link.text) driver.quit()
Abaixo são mostradas quatro das 218 âncoras que aparecen na resposta do programa. A primeira âncora tem href (https://www.python.org/#content) e texto (“Skip to content”). A segunda âncora só tem href (https://www.python.org/#python-network). A terceira âncora também só tem href (“javascript:;”). A quarta âncora não tem href (“None”), mas tem texto (“1”).
https://www.python.org/#content Skip to content https://www.python.org/#python-network javascript:; None 1
Para localizar apenas as âncoras que têm atributo “href”, basta alterar a linha abaixo. Neste caso, são obtidos 213 links.
links = driver.find_elements(By.XPATH, '//a[@href]')
Para eliminar também os links sem texto, é preciso alterar o código como mostrado abaixo. Agora são encontrados 141 links.
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By opcoes = webdriver.ChromeOptions() opcoes.headless = True driver = webdriver.Chrome(options=opcoes) driver.get('https://www.python.org') links = driver.find_elements(By.XPATH, '//a[@href]') n = 0 for link in links: if link.text != "": print(link.get_attribute('href')) print(link.text) n += 1 print("Número de links: ", n, "\n") driver.quit()
- Exemplo: Verifica qual a quantidade de <script>, com atributo “src”, na página oficial do Python.
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By opcoes = webdriver.ChromeOptions() opcoes.headless = True driver = webdriver.Chrome(options=opcoes) driver.get('https://www.python.org') nos = driver.find_elements(By.XPATH, '//script[@src]') print("Número de nós: " + str(len(nos)) + "\n") i = 0 for no in nos: i=i+1 print("*** i =", i, "src =", no.get_attribute('src')) driver.quit()
O programa apresenta a lista de oito nós. É importante observar que o primeiro nó listado abaixo é gerado pelo último script do <head> e inserido no início do próprio <head>. Os scripts restantes já estão definidos na página html.
Número de nós: 8 *** i = 1 src = https://ssl.google-analytics.com/ga.js *** i = 2 src = https://media.ethicalads.io/media/client/v1.4.0/ethicalads.min.js *** i = 3 src = https://www.python.org/static/js/libs/modernizr.js *** i = 4 src = https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js *** i = 5 src = https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js *** i = 6 src = https://www.python.org/static/js/libs/masonry.pkgd.min.js *** i = 7 src = https://www.python.org/static/js/libs/html-includes.js *** i = 8 src = https://www.python.org/static/js/main-min.dd72c1659644.js
O XPATH ‘/html/head//script[@src]’ informa que o <head> possui três scripts com atributo “src”, enquanto o XPATH ‘/html/body//script[@src]’ informa que existem cinco scripts com atributo “src” no <body>. Portanto, os três primeiros nós <script> da lista acima estão no <head> e os outros cinco nós estão no <body>.
O uso do XPATH ‘//script[@src][2]’ no programa fornece a seguinte resposta:
Número de nós: 2 *** i = 1 src = https://media.ethicalads.io/media/client/v1.4.0/ethicalads.min.js *** i = 2 src = https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js
A primeira linha mostra o segundo nó <script> descendente do <head> e a segunda linha mostra o segundo nó <script> descendente do <body>. Naturalmente que, apenas a primeira linha é apresentada com o XPATH ‘/html/head//script[@src][2]’ e apenas a segunda linha é apresentada com o XPATH ‘/html/body//script[@src][2]’.
O XPATH ‘//script[@src][last()]’ mostra o último script de <head> e o último script de <body>, ambos com atributo “src”.
O XPATH ‘//script[@src][position()<5]’ seleciona os scripts com índice menor que 5. Assim, são apresentados os três primeiros scripts do <head> e quatro primeiros scripts do <body>.
O uso de parênteses, englobando a expressão antes do índice, faz com que a lista de nós seja tratada como uma única lista, mesmo tendo sido selecinados os nós de <head> e de <body>. Assim, o XPATH ‘(//script[@src])[4]’ seleciona o quarto nó <script> da lista completa.
Número de nós: 1 *** i = 1 src = https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js
- Exemplo: Localiza as marcações meta, dentro do head, que possuem o atributo name. A resposta do programa mostra que existem treze nós <meta> com o atributo “name”.
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By opcoes = webdriver.ChromeOptions() opcoes.headless = True driver = webdriver.Chrome(options=opcoes) driver.get('https://www.python.org') nos = driver.find_elements(By.XPATH, '/html/head/meta[@name]') print("Número de nos: " + str(len(nos)) + "\n") driver.quit()
Outros exemplos são mostrados abaixo. Basta substituir o valor de XPATH procurado.
- Para localizar todas as marcações HTML que possuem o atributo “name”.
nos = driver.find_elements(By.XPATH, '//*[@name]')
2. Para localizar os elementos “button” da página:
nos = driver.find_elements(By.XPATH, '//button')
3. Para localizar os links que possuem a classe “donate-button”:
nos = driver.find_elements(By.XPATH, '//a[@class="donate-button"]')
4. Para localizar um cabeçalho <h2> com texto que contém a “Upcoming Events”:
nos = driver.find_elements(By.XPATH, '//h2[text()="Upcoming Events"]')
ou
nos = driver.find_elements(By.XPATH, '//h2[contains(text(),"Upcoming Events")]')
5. Para localizar uma <div> que é filha de outra <div>, digite:
nos = driver.find_elements(By.XPATH, '//div/div')
Para encontrar uma <div> que é descendente de outra <div>, mas que não é necessariamente sua filha, entre com:
nos = driver.find_elements(By.XPATH, '//div//div')
A primeira expressão // indica que pode existir qualquer quantidade de nós ascendentes antes da primeira <div>. A segunda expressão // indica que podem existir um ou mais nós no caminho entre as duas <div>.
No primeiro XPATH, são encontradas 28 <div> filhas; enquanto no segundo XPATH, são encontradas 48.
- Exemplo: Verifica quais nós possuem o texto “Docs”.
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By opcoes = webdriver.ChromeOptions() opcoes.headless = True driver = webdriver.Chrome(options=opcoes) driver.get('https://www.python.org') nos = driver.find_elements(By.XPATH, '//*[text()="Docs"]') print("Número de nós: " + str(len(nos)) + "\n") i = 0 for no in nos: i=i+1 print("*** i =", i) print("Text =", no.text) print("Tag_name =", no.tag_name, "\n") driver.quit()
A resposta mostra que existem quatro textos com “Docs” na página do Python.
Número de nós: 4 *** i = 1 Text = Docs Tag_name = a *** i = 2 Text = Tag_name = a *** i = 3 Text = Docs Tag_name = h2 *** i = 4 Text = Docs Tag_name = a
Note que o texto do segundo nó não é mostrado pelo programa. O motivo é que este nó é descendente de um nó com atributo ‘aria-hidden=”true”‘. Este atributo remove o texto do nó e de todos os seus filhos da árvore de acessibilidade. Para ver o texto do nó, neste caso, use o método “execute_script()” do Selenium para executar um script em JavaScript como mostrado abaixo.
print("Text =", driver.execute_script("return arguments[0].textContent", no))
Outra forma de localizar os textos dos nós é usando “.”(ponto) no lugar de “text()”.
nos = driver.find_elements(By.XPATH, '//*[.="Docs"]')
O programa agora encontra seis nós.
Número de nós: 6 *** i = 1 Text = Docs Tag_name = a *** i = 2 Text = Tag_name = li *** i = 3 Text = Tag_name = a *** i = 4 Text = Docs Tag_name = h2 *** i = 5 Text = Docs Tag_name = li *** i = 6 Text = Docs Tag_name = a
Isto ocorre porque o “.” considera todo o contexto onde se encontra o texto procurado. Abaixo o código HTML da página Python usado neste exemplo. O primeiro caso (“text()”) seleciona apenas um nó (<a>). O segundo caso (“.”) seleciona 2 nós (<li> e <a>), pois o texto “Docs” existe dentro de uma âncora (<a>) que está dentro de uma lista (<li>). Devido ao atributo “aria-hidden”, o texto “Docs” não é mostrado nos dois nós.

O uso de “contains” permite definir uma parte do texto do nó. Assim,
nos = driver.find_elements(By.XPATH, '//*[contains(text(),"Docs")]')
seleciona todos os nós com texto que possui a string “Docs” como “Non-English Docs”. Neste caso são encontrados 6 nós. A substituição de “text()” por “.” faz com que o programa encontre 34 nós, pois a busca considera todo o contexto de cada nó com “Docs”.
- Exemplo: Verifica na página Python quais listas não ordenadas (ul) possuem o atributo role igual a “menu” ou igual a “tree”.
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By opcoes = webdriver.ChromeOptions() opcoes.headless = True driver = webdriver.Chrome(options=opcoes) driver.get('https://www.python.org') nos = driver.find_elements(By.XPATH, '//ul[@role = "menu" or @role = "tree"]') print("Número de nós: " + str(len(nos)) + "\n") for no in nos: print(no.get_attribute('role')) driver.quit()
A resposta do programa informa que existem 10 nós: 7 nós com atributo role igual a “menu” e 3 nós com atributo role igual a “tree”.
Para verificar os nós com atributo role que não são iguais nem a “menu” e nem a “tree”, use ‘//ul[@role != “menu” and @role != “tree”]’. O programa encontra apenas 1 nó com valor “menubar”.
- Exemplo: Localiza os nós que no texto do atributo “datetime” existe a string “2022-07-06”.
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By opcoes = webdriver.ChromeOptions() opcoes.headless = True driver = webdriver.Chrome(options=opcoes) driver.get('https://www.python.org') nos = driver.find_elements(By.XPATH, "//time[contains(@datetime, '2022-07-06')]"); print("Número de nós: " + str(len(nos)) + "\n") for no in nos: data = no.get_attribute('datetime'); print(data); driver.quit()
A resposta mostrada pelo programa quando executado em 08/07/22:
Número de nós: 1 2022-07-06T16:32:00.000002+00:00
O XPATH “//time[not(contains(@datetime, ‘2022-07-06’))]” mostra todos os nós <time> que não contém “2022-07-06”.
Número de nós: 9 2022-07-01T13:31:00.000004+00:00 2022-06-19T12:04:00.000006+00:00 2022-06-09T18:02:00.000003+00:00 2022-06-08T15:25:00.000002+00:00 2022-07-09T00:00:00+00:00 2022-07-11T00:00:00+00:00 2022-07-11T00:00:00+00:00 2022-07-12T18:00:00+00:00 2022-08-15T00:00:00+00:00
É possível colocar várias condições usando operadores como “not”, “or” e “and”. Por exemplo, o XPATH “//time[contains(@datetime, ‘2022’) and not(contains(@datetime,’00:00:00+00:00′))]” fornece como resposta:
Número de nós: 6 2022-07-06T16:32:00.000002+00:00 2022-07-01T13:31:00.000004+00:00 2022-06-19T12:04:00.000006+00:00 2022-06-09T18:02:00.000003+00:00 2022-06-08T15:25:00.000002+00:00 2022-07-12T18:00:00+00:00
O XPATH “//time[contains(text(), ’07-06′)]” seleciona apenas um nó com texto “07-06” na página. O código HTML deste nó é mostrado abaixo.

- Exemplo: Considere o código HTML abaixo extraído da página oficial Python.

Para localizar o elemento indicado na imagem como “Elemento-filho”, entre com o código abaixo.
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By opcoes = webdriver.ChromeOptions() opcoes.headless = True driver = webdriver.Chrome(options=opcoes) driver.get('https://www.python.org') nos = driver.find_elements(By.XPATH, '//div[@class="success-story-item"]') print("Número de nós: " + str(len(nos)) + "\n") for no in nos: print("Class =", no.get_attribute('class')) print("Id =", no.get_attribute('id')) driver.quit()
O programa só localiza um nó com a definição fornecida.
Número de nós: 1 Class = success-story-item Id = success-story-838
Para localizar o pai do nó acima, basta adicionar ‘/..’ ao final do XPATH, ou seja, ‘//div[@class=”success-story-item”]/..’. A resposta do programa é
Número de nós: 1 Class = shrubbery Id =
Pode-se usar “/..” para cada nível hierárquico que se deseja ascender. Assim, para obter informações sobre o avô do nó use ‘//div[@class=”success-story-item”]/../..’.
O XPATH ‘//p[@class=”give-me-more”]//parent::div’ localiza nós <div> que são pais de parágrafos com classe “give-me-more”. Note que o nó de interesse na pesquisa é o nó-pai. Exitem 4 nós div que são pais de parágrafos com classe “give-me-more” na página do Python.
O XPATH ‘//p[@class=”give-me-more”]//parent::div[@class=”shrubbery”]’ localiza os nós <div> com classe “shrubbery” que são pais de parágrafos com classe “give-me-more”.
Use ‘//p[@class=”give-me-more”]//parent::*’ quando os nós procurados podem ser de qualquer tipo desde que tenha um filho que é um parágrafo com classe “give-me-more”.
Para localizar os parágrafos que são filhos de uma <div> com classe “shrubbery”, use ‘//div[@class=”shrubbery”]//child::p’. O programa encontra 5 nós. Ao substituir p por *, o programa selecionará todos os filhos das <div> com classe “”shrubbery”. A resposta do programa agora é 104.
Para localizar parágrafos com classe “give-me-more” que são filhos de uma div com classe “shrubbery”, basta usar ‘//div[@class=”shrubbery”]//child::p[@class=”give-me-more”]’. O programa encontra 4 nós.
É possível também localizar nós irmãos (mesmo nó-pai) que aparecem antes ou depois de um determinado nó. Por exemplo, ‘//p[@class=”give-me-more”]/preceding-sibling::*’ identifica o nó-irmão (de qualquer tipo) que vem antes do parágrafo com classe “give-me-more”. Já o XPATH ‘//h2[@class=”widget-title”]/following-sibling::div’ localiza os nós div que aparecem depois de um h2.
É importante observar que o uso de / ou de //, antes de quaiquer definição de parentesco (filho, pai, irmão, etc), não altera a resposta fornecida pelo programa.
Raspagem de Dados
Para identificar o XPATH de um nó basta seguir dois passos:
- Clicar com o botão direiro em cima do campo desejado e selecionar “inspecionar”;
- Clicar novamente com o botão direito em cima do texto marcado no item anterior e selecionar “Copiar” e em seguida “XPath”.

- Exemplo: Acessa o Google, escreve “unirio” no campo de pesquisa e pressiona o botão “Estou com sorte”.
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys opcoes = webdriver.ChromeOptions() #opcoes.headless = True driver = webdriver.Chrome(options=opcoes) driver.get('https://www.google.com.br') no_pesq = driver.find_element(By.XPATH, '/html/body/div[1]/div[3]/form/div[1]/div[1]/div[1]/div/div[2]/input') no_pesq.clear() no_pesq.send_keys("unirio") no_sort = driver.find_element(By.XPATH, '/html/body/div[1]/div[3]/form/div[1]/div[1]/div[3]/center/input[2]') no_sort.click();
- Exemplo: Pesquisa, no Portal da Transparência, o total das despesas pagas pelas quatro universidades cariocas no ano anterior.O programa não trata a possibilidade do aparecimento de uma tela de captcha.
from selenium import webdriver from selenium.webdriver.chrome.options import Options from selenium.webdriver.common.by import By from selenium.webdriver.common.keys import Keys opcoes = webdriver.ChromeOptions() opcoes.headless = True driver = webdriver.Chrome(options=opcoes) universidades = { "UFF" : 26236, "UFRJ" : 26245, "UFRRJ" : 26249, "UNIRIO": 26269 } for uni in universidades: nome='https://www.portaltransparencia.gov.br/orgaos/'+ str(universidades[uni]) driver.get(nome) no_ano = driver.find_element(By.XPATH, '/html/body/main/div[2]/div/div[2]/div/ul/li[4]/a') ano = str(no_ano.text) no_ano.click() no_valor = driver.find_element(By.XPATH, '/html/body/main/div[3]/div/div[2]/div[2]/div[1]/div[2]/div/table/tbody/tr[3]/td[2]/b') print("Total de pagamentos realizados pela " + uni + " em " + ano + " = " + str(no_valor.text))
O primeiro nó selecionado (e depois clicado) corresponde ao do ano anterior à data de acesso do site. O site marca inicialmente o ano atual.

O segundo nó selecionado é o que contém o valor procurado pelo programa.

A resposta do programa é
Total de pagamentos realizados pela UFF em 2021 = R$ 2.096.577.771,75 Total de pagamentos realizados pela UFRJ em 2021 = R$ 3.671.253.625,11 Total de pagamentos realizados pela UFRRJ em 2021 = R$ 609.048.608,81 Total de pagamentos realizados pela UNIRIO em 2021 = R$ 591.228.972,98