Formatos e fontes de dados 9 min de leitura

Parsing de URL: o que é, para que serve e como se implementa em diferentes linguagens

Parsing de URL: do que se compõe um endereço, como decompor e montar links e como lidar com parâmetros de consulta e codificação em várias linguagens.

EW
Equipe Web-Scraping.biz
Coleta de dados para as demandas do negócio
Publicado: 17 abril 2025

O parsing de URL (do inglês parse, «analisar») é a decomposição do endereço de uma página web em suas partes constituintes: o protocolo, o domínio, a porta, o caminho, os parâmetros de consulta e o fragmento. De uma string «bruta» como https://example.com/catalog?page=2 obtemos um objeto estruturado, em que cada campo pode ser consultado separadamente e, se necessário, modificado.

À primeira vista, a tarefa parece trivial: «fatiar uma string por caracteres». Na prática, as URLs têm uma especificação formal (RFC 3986) com uma infinidade de nuances: codificação de caracteres especiais, links relativos, partes opcionais do endereço, normalização. Por isso quase todas as linguagens incluem uma ferramenta padrão para parsear URLs, e escrever uma análise própria com expressões regulares praticamente nunca é necessário.

Do que se compõe uma URL

Vamos analisar um endereço o mais «completo» possível para ver todos os componentes:

code
https://user:pass@example.com:8080/catalog/items?page=2&sort=price#reviews
└─┬─┘   └──┬───┘ └────┬────┘└─┬─┘└─────┬──────┘ └──────┬──────┘ └──┬──┘
scheme  userinfo    host    port      path             query     fragment
Componente Valor no exemplo Função
scheme (esquema) https Protocolo de acesso: http, https, ftp, mailto etc.
userinfo user:pass Credenciais (pouco usado, sobretudo para FTP/basic auth)
host example.com Nome de domínio ou endereço IP
port (porta) 8080 Porta; quando não é indicada, vale a padrão do esquema (80 para http, 443 para https)
path (caminho) /catalog/items Caminho até o recurso no servidor
query (consulta) page=2&sort=price Parâmetros de consulta no formato «chave=valor»
fragment (âncora) reviews Referência a uma seção específica dentro da página; não é enviado ao servidor

São exatamente essas as partes que o parser extrai. Com elas já dá para trabalhar: obter o valor de um parâmetro GET específico, substituir o domínio, descartar o fragmento ou montar uma nova URL a partir dos componentes modificados.

Para que serve o parsing de URL

O parsing de URL aparece em praticamente qualquer aplicação que trabalhe com endereços web. Os cenários mais frequentes:

  • Extração dos parâmetros de consulta. É preciso saber em que página do catálogo o usuário está (?page=5), qual filtro ele escolheu ou qual tag UTM chegou junto. O parser converte a query string em um dicionário prático.
  • Validação e sanitização de links. Antes de salvar no banco uma URL enviada pelo usuário ou de usá-la em um redirecionamento, é importante conferir se o esquema é permitido (que não seja javascript:, por exemplo) e se o domínio consta na lista de permissões.
  • Roteamento. Os frameworks web analisam o caminho e os parâmetros para determinar qual controller invocar.
  • Análises e registro de logs. Para agrupar os acessos por domínio ou por caminho, primeiro é preciso decompor os endereços em partes.
  • Web scraping e crawling. Aqui o parsing de URL é especialmente importante; falamos dele em detalhe mais abaixo.

O parsing de URL na construção de crawlers

Um crawler (robô de rastreamento) percorre um site passando de página em página através dos links. Para entender em que o crawling difere do scraping e do parsing propriamente dito, recomendamos ler antes o nosso material «Scraping, parsing e crawling: quais as diferenças?». Em resumo: o crawler cuida do percurso e da descoberta das páginas; o scraper, da extração dos dados; e o parsing, da análise do conteúdo obtido, endereços incluídos.

A principal «armadilha» ao percorrer um site está no fato de que os links do HTML quase sempre são relativos, não absolutos. Na marcação você encontrará:

html
<a href="/about">Quem somos</a>
<a href="../catalog/phones">Telefones</a>
<a href="page2.html">Próxima</a>
<a href="#reviews">Avaliações</a>

O robô não pode seguir o link /about nem page2.html tal como estão: não são endereços completos. Para continuar o rastreamento, o link relativo precisa ser convertido em absoluto tomando como referência o endereço da página atual (a URL base). É disso, justamente, que o parsing de URL cuida:

URL base da página Link relativo Resultado (URL absoluta)
https://example.com/catalog/items/ /about https://example.com/about
https://example.com/catalog/items/ ../phones https://example.com/catalog/phones
https://example.com/catalog/items/ page2.html https://example.com/catalog/items/page2.html
https://example.com/catalog/items/ https://cdn.example.com/x https://cdn.example.com/x (já é absoluta)

Essa operação chama-se resolução do link (URL resolution), e quase todas as linguagens oferecem uma função pronta para isso: urljoin em Python, o construtor new URL(href, base) em JavaScript, URI.resolve() em Java, ResolveReference() em Go.

Normalização e eliminação de duplicatas

Além de converter os links em absolutos, interessa ao crawler normalizar os endereços para não percorrer a mesma página várias vezes. Técnicas habituais:

  • descartar o fragmento #fragment: ele aponta para uma área dentro da página, não para um recurso à parte (/page#top e /page são a mesma página);
  • passar o esquema e o domínio para minúsculas;
  • remover a porta padrão (:443 no https);
  • ordenar ou filtrar os parâmetros de consulta (por exemplo, remover as tags UTM).

Após a normalização, as URLs absolutas são guardadas no conjunto de endereços já visitados: assim o robô não entra em loops nem faz requisições a mais.

Exemplos de implementação de parsers de URL

A seguir, como decompor uma URL em partes e como resolver um link relativo com as ferramentas padrão das linguagens mais populares.

Python

Na biblioteca padrão, quem cuida de tudo é o módulo urllib.parse.

python
from urllib.parse import urlparse, urljoin, urldefrag, parse_qs

url = "https://example.com:8080/catalog/items?page=2&sort=price#reviews"
parsed = urlparse(url)

print(parsed.scheme)    # https
print(parsed.hostname)  # example.com
print(parsed.port)      # 8080
print(parsed.path)      # /catalog/items
print(parsed.query)     # page=2&sort=price
print(parsed.fragment)  # reviews

# Parâmetros de consulta -> dicionário
print(parse_qs(parsed.query))  # {'page': ['2'], 'sort': ['price']}

# Resolução de um link relativo (para o crawler)
base = "https://example.com/catalog/items/"
print(urljoin(base, "../about"))    # https://example.com/catalog/about
print(urljoin(base, "/contacts"))   # https://example.com/contacts
print(urljoin(base, "page2.html"))  # https://example.com/catalog/items/page2.html

# Descartar o fragmento ao normalizar
print(urldefrag("https://example.com/page#reviews")[0])  # https://example.com/page

JavaScript (navegador e Node.js)

A classe integrada URL funciona igual no navegador e no Node.js. Ela também sabe resolver links relativos: para isso, o endereço base é passado como segundo argumento.

javascript
const url = new URL("https://example.com:8080/catalog/items?page=2&sort=price#reviews");

console.log(url.protocol);  // "https:"
console.log(url.hostname);  // "example.com"
console.log(url.port);      // "8080"
console.log(url.pathname);  // "/catalog/items"
console.log(url.search);    // "?page=2&sort=price"
console.log(url.hash);      // "#reviews"

// Parâmetros de consulta
console.log(url.searchParams.get("page"));  // "2"

// Resolução de um link relativo
const base = "https://example.com/catalog/items/";
console.log(new URL("../about", base).href);   // "https://example.com/catalog/about"
console.log(new URL("/contacts", base).href);  // "https://example.com/contacts"

PHP

A análise básica fica por conta de parse_url(), e parse_str() converte a query string em um array.

php
$url = "https://example.com:8080/catalog/items?page=2&sort=price#reviews";
$parts = parse_url($url);

echo $parts['scheme'];    // https
echo $parts['host'];      // example.com
echo $parts['port'];      // 8080
echo $parts['path'];      // /catalog/items
echo $parts['fragment'];  // reviews

parse_str($parts['query'], $query);
print_r($query);          // ['page' => '2', 'sort' => 'price']

No PHP não existe um equivalente embutido do urljoin; por isso, para resolver links relativos nos crawlers costuma-se adotar uma biblioteca — por exemplo, league/uri ou os helpers do Guzzle (GuzzleHttp\Psr7\UriResolver).

Java

A biblioteca padrão inclui a classe java.net.URI para trabalhar com endereços. O método resolve() entrega diretamente a resolução do link relativo.

java
import java.net.URI;

URI uri = URI.create("https://example.com:8080/catalog/items?page=2&sort=price#reviews");

System.out.println(uri.getScheme());    // https
System.out.println(uri.getHost());      // example.com
System.out.println(uri.getPort());      // 8080
System.out.println(uri.getPath());      // /catalog/items
System.out.println(uri.getQuery());     // page=2&sort=price
System.out.println(uri.getFragment());  // reviews

// Resolução de um link relativo
URI base = URI.create("https://example.com/catalog/items/");
System.out.println(base.resolve("../about"));   // https://example.com/catalog/about
System.out.println(base.resolve("/contacts"));  // https://example.com/contacts

Go

O pacote net/url da biblioteca padrão cobre tanto a análise quanto a resolução de links (ResolveReference).

go
package main

import (
    "fmt"
    "net/url"
)

func main() {
    u, _ := url.Parse("https://example.com:8080/catalog/items?page=2&sort=price#reviews")

    fmt.Println(u.Scheme)               // https
    fmt.Println(u.Hostname())           // example.com
    fmt.Println(u.Port())               // 8080
    fmt.Println(u.Path)                 // /catalog/items
    fmt.Println(u.RawQuery)             // page=2&sort=price
    fmt.Println(u.Query().Get("page"))  // 2

    // Resolução de um link relativo
    base, _ := url.Parse("https://example.com/catalog/items/")
    ref, _ := url.Parse("../about")
    fmt.Println(base.ResolveReference(ref))  // https://example.com/catalog/about
}

Exemplo prático: coletando todos os links de uma página

Vamos juntar tudo no passo típico de um crawler: parsear o HTML, extrair todos os links e convertê-los em absolutos. Um exemplo em Python com requests e BeautifulSoup:

python
import requests
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urldefrag

def extract_links(page_url: str) -> set[str]:
    response = requests.get(page_url, timeout=10)
    soup = BeautifulSoup(response.text, "html.parser")

    links = set()
    for a in soup.find_all("a", href=True):
        # 1. convertemos o link relativo em absoluto
        absolute = urljoin(page_url, a["href"])
        # 2. descartamos o fragmento para não gerar duplicatas
        absolute, _ = urldefrag(absolute)
        # 3. deixamos apenas os links http(s)
        if absolute.startswith(("http://", "https://")):
            links.add(absolute)

    return links

for link in extract_links("https://example.com/catalog/"):
    print(link)

Aqui o parsing de URL cumpre duas funções-chave: urljoin transforma os href relativos em endereços completos que o robô poderá seguir depois, e urldefrag evita tratar /page e /page#top como páginas distintas.

Erros frequentes

  • Parsear as URLs com expressões regulares. Pela abundância de casos-limite da especificação, uma análise caseira quase sempre sai incompleta. Use as bibliotecas padrão.
  • Esquecer os links relativos. Sem a conversão para absoluto, o crawler «tropeça» já no primeiro link interno.
  • Não normalizar os endereços. Sem descartar o fragmento, ordenar os parâmetros e unificar maiúsculas e minúsculas, o robô percorre as mesmas páginas repetidas vezes.
  • Confiar no esquema sem conferir. Antes de um redirecionamento ou de inserir um link, certifique-se de que o esquema é seguro (http/https); caso contrário, fica aberta a porta para um XSS via javascript:.

Conclusão

O parsing de URL é uma operação básica, mas importante: converte um endereço em forma de string em uma estrutura com a qual é cômodo trabalhar. Nas aplicações comuns, serve para extrair parâmetros, validar e rotear; nos crawlers, torna-se crítico: sem converter os links relativos em absolutos e sem normalização, percorrer um site é simplesmente impossível. A boa notícia é que quase todas as linguagens incluem para isso uma ferramenta padrão e confiável, de modo que não é preciso reinventar a roda.