Parsing d'URL : définition, usages et implémentation dans différents langages

Parsing d'URL : de quoi se compose une adresse, comment décomposer et assembler les liens, gérer les paramètres de requête et l'encodage dans différents langages.

ÉW
Équipe Web-Scraping.fr
Collecte de données pour votre activité
Publié le: 17 avril 2025

Le parsing d'URL (de l'anglais parse, « analyser ») est la décomposition de l'adresse d'une page web en ses parties constitutives : protocole, domaine, port, chemin, paramètres de requête et ancre. D'une chaîne « brute » comme https://example.com/catalog?page=2, on obtient un objet structuré dont chaque champ est accessible séparément et modifiable au besoin.

À première vue, la tâche semble triviale — « découper la chaîne sur des séparateurs ». En pratique, l'URL a une spécification formelle (RFC 3986) avec une foule de subtilités : encodage des caractères spéciaux, liens relatifs, parties facultatives de l'adresse, normalisation. C'est pourquoi presque chaque langage possède un outil standard de parsing d'URL, et écrire son propre découpage avec des expressions régulières n'est pratiquement jamais nécessaire.

De quoi se compose une URL

Décomposons une adresse la plus « complète » possible pour voir tous les composants :

code
https://user:pass@example.com:8080/catalog/items?page=2&sort=price#reviews
└─┬─┘   └──┬───┘ └────┬────┘└─┬─┘└─────┬──────┘ └──────┬──────┘ └──┬──┘
scheme  userinfo    host    port      path             query     fragment
Composant Valeur dans l'exemple Rôle
scheme (schéma) https Protocole d'accès : http, https, ftp, mailto, etc.
userinfo user:pass Identifiants (rarement utilisé, surtout pour FTP/basic-auth)
host (hôte) example.com Nom de domaine ou adresse IP
port (port) 8080 Port ; s'il n'est pas indiqué, on prend le standard du schéma (80 pour http, 443 pour https)
path (chemin) /catalog/items Chemin vers la ressource sur le serveur
query (requête) page=2&sort=price Paramètres de requête au format « clé=valeur »
fragment (ancre) reviews Renvoi vers une section précise de la page ; n'est pas envoyé au serveur

Ce sont précisément ces parties que le parseur extrait. On peut ensuite travailler avec : récupérer la valeur d'un paramètre GET précis, remplacer le domaine, écarter l'ancre, assembler une nouvelle URL à partir des composants modifiés.

À quoi sert le parsing d'URL

Le parsing d'URL apparaît dans pratiquement toute application qui manipule des adresses web. Les scénarios les plus fréquents :

  • Extraction des paramètres de requête. Il faut savoir sur quelle page du catalogue se trouve l'utilisateur (?page=5), quel filtre est choisi ou quel tag UTM est présent. Le parseur transforme la chaîne de requête en dictionnaire commode.
  • Validation et assainissement des liens. Avant d'enregistrer une URL fournie par l'utilisateur ou de l'insérer dans une redirection, il faut s'assurer que le schéma est autorisé (par exemple, pas javascript:) et que le domaine figure dans la liste blanche.
  • Routage. Les frameworks web décomposent le chemin et les paramètres pour déterminer quel gestionnaire appeler.
  • Analytique et logs. Pour regrouper les accès par domaines ou chemins, on commence par décomposer les adresses.
  • Web scraping et crawling. Ici, le parsing d'URL est particulièrement important — nous y venons en détail.

Le parsing d'URL dans la construction de crawlers

Le crawler (robot d'exploration) parcourt un site en suivant les liens de page en page. Pour bien saisir ce qui distingue le crawling du scraping et du parsing proprement dit, nous recommandons de lire d'abord notre article « Scraping, parsing et crawling : quelles différences ? ». En bref : le crawler se charge du parcours et de la découverte des pages, le scraper — de l'extraction des données, et le parsing — de l'analyse du contenu obtenu, adresses comprises.

Le grand « piège » du parcours d'un site : les liens dans le HTML sont presque toujours relatifs, et non absolus. Dans le balisage, vous rencontrerez :

html
<a href="/about">À propos</a>
<a href="../catalog/phones">Téléphones</a>
<a href="page2.html">Suivante</a>
<a href="#reviews">Avis</a>

Le robot ne peut pas suivre directement le lien /about ou page2.html — ce ne sont pas des adresses complètes. Pour poursuivre le parcours, le lien relatif doit être converti en forme absolue en s'appuyant sur l'adresse de la page courante (l'URL de base). C'est exactement le rôle du parsing d'URL :

URL de base de la page Lien relatif Résultat (URL absolue)
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 (déjà absolue)

Cette opération s'appelle la résolution de lien (URL resolution), et presque tous les langages ont une fonction prête pour cela : urljoin en Python, le constructeur new URL(href, base) en JavaScript, URI.resolve() en Java, ResolveReference() en Go.

Normalisation et élimination des doublons

Au-delà de la conversion en absolu, le crawler doit normaliser les adresses pour ne pas parcourir plusieurs fois la même page. Techniques typiques :

  • écarter l'ancre #fragment — elle pointe vers une zone à l'intérieur de la page, pas vers une ressource distincte (/page#top et /page, c'est la même page) ;
  • mettre le schéma et le domaine en minuscules ;
  • retirer le port standard (:443 pour https) ;
  • ordonner ou filtrer les paramètres de requête (par exemple, jeter les tags UTM).

Après normalisation, les URL absolues sont stockées dans l'ensemble des adresses déjà visitées — ainsi le robot ne tourne pas en rond et ne fait pas de requêtes superflues.

Exemples d'implémentation de parseurs d'URL

Voici comment décomposer une URL et résoudre un lien relatif avec les outils standard des langages populaires.

Python

Dans la bibliothèque standard, tout passe par le module 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

# Paramètres de requête -> dictionnaire
print(parse_qs(parsed.query))  # {'page': ['2'], 'sort': ['price']}

# Résolution d'un lien relatif (pour le 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

# Écarter l'ancre lors de la normalisation
print(urldefrag("https://example.com/page#reviews")[0])  # https://example.com/page

JavaScript (navigateur et Node.js)

La classe intégrée URL fonctionne à l'identique dans le navigateur et dans Node.js. Elle sait aussi résoudre les liens relatifs — l'adresse de base se passe en second argument.

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"

// Paramètres de requête
console.log(url.searchParams.get("page"));  // "2"

// Résolution d'un lien relatif
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

La décomposition de base est assurée par parse_url(), et parse_str() transforme la chaîne de requête en tableau.

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']

PHP n'a pas d'équivalent intégré de urljoin ; pour résoudre les liens relatifs dans les crawlers, on branche donc habituellement une bibliothèque — par exemple league/uri ou les helpers de Guzzle (GuzzleHttp\Psr7\UriResolver).

Java

La bibliothèque standard offre la classe java.net.URI pour travailler avec les adresses. La méthode resolve() donne directement la résolution d'un lien relatif.

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

// Résolution d'un lien relatif
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

Le paquet net/url de la bibliothèque standard couvre aussi bien la décomposition que la résolution de liens (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

    // Résolution d'un lien relatif
    base, _ := url.Parse("https://example.com/catalog/items/")
    ref, _ := url.Parse("../about")
    fmt.Println(base.ResolveReference(ref))  // https://example.com/catalog/about
}

Exemple pratique : collecter tous les liens d'une page

Assemblons le tout — l'étape typique d'un crawler : parser le HTML, récupérer tous les liens et les convertir en absolu. Exemple en Python avec requests et 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. on convertit le lien relatif en absolu
        absolute = urljoin(page_url, a["href"])
        # 2. on écarte l'ancre pour ne pas multiplier les doublons
        absolute, _ = urldefrag(absolute)
        # 3. on ne garde que les liens http(s)
        if absolute.startswith(("http://", "https://")):
            links.add(absolute)

    return links

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

Ici, le parsing d'URL remplit deux missions clés : urljoin transforme les href relatifs en adresses complètes que le robot pourra suivre, et urldefrag évite de compter /page et /page#top comme deux pages différentes.

Erreurs fréquentes

  • Parser les URL avec des expressions régulières. Vu l'abondance de cas limites dans la spécification, un découpage maison se révèle presque toujours incomplet. Utilisez les bibliothèques standard.
  • Oublier les liens relatifs. Sans conversion en absolu, le crawler « trébuche » dès le premier lien interne.
  • Ne pas normaliser les adresses. Sans écarter l'ancre, ordonner les paramètres et unifier la casse, le robot parcourt les mêmes pages en boucle.
  • Faire confiance au schéma sans vérification. Avant une redirection ou l'insertion d'un lien, assurez-vous que le schéma est sûr (http/https), sinon la porte s'ouvre au XSS via javascript:.

Conclusion

Le parsing d'URL est une opération basique mais importante : elle transforme une chaîne-adresse en structure commode à manipuler. Dans les applications ordinaires, il sert à extraire les paramètres, valider et router ; dans les crawlers, il devient critique — sans conversion des liens relatifs en absolu et sans normalisation, le parcours d'un site est tout simplement impossible. La bonne nouvelle : presque chaque langage dispose pour cela d'un outil standard fiable, et il n'y a pas à réinventer la roue.