La plupart des crawlers découvrent les pages de la manière la plus coûteuse : récupérer une page, en extraire les liens, les mettre en file d’attente, recommencer. Cela fonctionne, mais cela consacre l’essentiel du budget à la navigation, aux pages de listing et aux pages déjà vues, et peut malgré tout manquer des pages vers lesquelles rien ne pointe.
De nombreux sites publient délibérément une liste de leurs URL. Les sitemaps XML existent pour que les moteurs de recherche puissent trouver les pages efficacement, et ce même fichier indique à une équipe data ce qui existe sur un site, comment il est organisé et, parfois, ce qui a récemment changé. Ce guide explique comment trouver et lire correctement les sitemaps, et pourquoi le champ le plus utile qu’ils contiennent, lastmod, doit être vérifié avant d’y accorder sa confiance. Nous l’avons vérifié sur deux sites réels, et il a échoué de deux manières différentes.
Points clés
- Un sitemap liste jusqu’à 50 000 URL par fichier, et un index de sitemaps peut lister jusqu’à 50 000 sitemaps, si bien que même les très grands sites peuvent publier un inventaire complet.
- Les sitemaps sont généralement déclarés dans le robots.txt via une ligne
Sitemap:; vérifiez-la avant de deviner un emplacement. lastmodest le champ qui pourrait vous épargner le plus de récupérations, et c’est le moins fiable. Google indique qu’il n’utiliselastmodque si c’est « de façon cohérente et vérifiable » exact.- Dans notre vérification, le sitemap d’actualités d’un grand éditeur de presse attribuait à chaque entrée le même horodatage, celui du moment de génération du fichier. Une vaste archive documentaire publiait plus de 10 000 URL sans aucun
lastmod. - Utilisez les sitemaps pour la découverte, vérifiez
lastmodsite par site avant de planifier dessus, et conservez le crawling par liens comme filet de sécurité.
Ce que le protocole permet
Le protocole des sitemaps est court et mérite d’être connu précisément :
| Règle | Détail |
|---|---|
| Limites de taille | « pas plus de 50 000 URL » et « pas plus de 50 Mo (52 428 800 octets) » par fichier sitemap, non compressé |
| Index de sitemaps | Un fichier listant d’autres sitemaps, avec les mêmes limites de 50 000 entrées et 50 Mo |
| Compression | Les fichiers peuvent être compressés en gzip, tant qu’ils restent dans la limite une fois décompressés |
lastmod | Facultatif, au format W3C Datetime, qui peut être une simple date, du type YYYY-MM-DD |
| Découverte | Une ligne Sitemap: dans le robots.txt ; un site peut en lister plusieurs |
Deux champs facultatifs que vous rencontrerez, changefreq et priority, peuvent être ignorés. Google indique clairement qu’il « ignore les valeurs <priority> et <changefreq> », et il y a peu de raisons pour quiconque d’autre de leur accorder confiance non plus.
Les sites d’actualités publient souvent un sitemap d’actualités séparé, couvrant uniquement les articles récents, avec des champs supplémentaires comme une date de publication. Ces fichiers sont petits, régénérés fréquemment, et très utiles pour suivre le contenu récent.
Bien lire les sitemaps
Un lecteur robuste doit faire quatre choses : trouver les sitemaps depuis le robots.txt, gérer le gzip, suivre récursivement les index de sitemaps, et parser lastmod en quelque chose de comparable. Il doit aussi plafonner le nombre de fichiers récupérés, car un index peut pointer vers des milliers d’entre eux.
import gzip
import io
import re
import urllib.request
from datetime import datetime, timezone
from defusedxml.ElementTree import fromstring # pip install defusedxml
NS = "{http://www.sitemaps.org/schemas/sitemap/0.9}"
UA = "Mozilla/5.0 (compatible; sitemap-reader)"
MAX_BYTES = 52_428_800 # la limite du protocole de 50MB, non compressé
def fetch(url, opener=None):
opener = opener or urllib.request.build_opener()
req = urllib.request.Request(url, headers={"User-Agent": UA})
with opener.open(req, timeout=45) as r:
body = r.read(MAX_BYTES + 1)
if body[:2] == b"\x1f\x8b":
body = gzip.GzipFile(fileobj=io.BytesIO(body)).read(MAX_BYTES + 1)
if len(body) > MAX_BYTES:
raise ValueError(f"{url} exceeds the 50MB sitemap limit")
return body
def sitemap_roots(origin, opener=None):
"""Sitemaps déclarés dans robots.txt, avec repli sur /sitemap.xml."""
try:
robots = fetch(origin.rstrip("/") + "/robots.txt", opener).decode("utf-8", "replace")
found = re.findall(r"(?im)^\s*sitemap:\s*(\S+)", robots)
except OSError:
found = []
return found or [origin.rstrip("/") + "/sitemap.xml"]
def parse_lastmod(value):
if not value:
return None
value = value.strip().replace("Z", "+00:00")
try:
dt = datetime.fromisoformat(value)
except ValueError:
return None
return dt if dt.tzinfo else dt.replace(tzinfo=timezone.utc)
def walk(url, opener=None, max_files=20, _seen=None):
"""Yield (loc, lastmod) from a sitemap or sitemap index, following nested indexes."""
seen = _seen if _seen is not None else set()
if url in seen or len(seen) >= max_files:
return
seen.add(url)
root = fromstring(fetch(url, opener))
if root.tag == NS + "sitemapindex":
children = sorted(root.findall(NS + "sitemap"),
key=lambda s: parse_lastmod(s.findtext(NS + "lastmod")) or datetime.min.replace(tzinfo=timezone.utc),
reverse=True)
for child in children:
yield from walk(child.findtext(NS + "loc").strip(), opener, max_files, seen)
else:
for u in root.findall(NS + "url"):
yield u.findtext(NS + "loc").strip(), parse_lastmod(u.findtext(NS + "lastmod"))
def changed_since(origin, since, opener=None, max_files=20):
"""URLs whose sitemap lastmod is newer than `since`, plus those with no lastmod at all."""
changed, undated, total = [], [], 0
for root in sitemap_roots(origin, opener):
for loc, lastmod in walk(root, opener, max_files):
total += 1
if lastmod is None:
undated.append(loc)
elif lastmod > since:
changed.append((loc, lastmod))
return {"total": total, "changed": changed, "undated": undated}
Le parcoureur d’index visite les sitemaps enfants du plus récent au plus ancien lorsque l’index fournit des dates, si bien qu’une exécution plafonnée lit d’abord les parties les plus récemment mises à jour d’un grand site. Deux détails sont là par sécurité. Un sitemap est une entrée non fiable provenant du serveur de quelqu’un d’autre, le code le parse donc avec defusedxml, qui refuse les astuces d’entités capables de faire gonfler un petit fichier à plusieurs gigaoctets avec les parseurs XML standards, et il plafonne à la fois le téléchargement et la taille décompressée à la limite de 50 Mo du protocole, si bien qu’un fichier compressé ne peut pas gonfler sans limite. Le paramètre opener permet de faire passer les requêtes par un proxy quand il faut voir une version d’un site spécifique à un marché, la même approche que pour toute autre récupération.
Ne faire confiance à lastmod qu’après vérification
lastmod promet exactement ce dont la collecte incrémentale a besoin : une liste de ce qui a changé depuis la dernière exécution. Si c’était fiable partout, un crawler pourrait ne récupérer que les pages modifiées et ignorer tout le reste. Ce n’est pas fiable partout, et nos deux sites de test illustrent les deux échecs courants.
Premier échec : lastmod correspond à l’heure de génération. Nous avons lu le sitemap d’actualités d’un grand éditeur de presse. Chaque entrée datée portait l’un de deux horodatages, à une seconde d’écart : le moment de génération du fichier, pas le moment où chaque article a changé. Filtrer sur « modifié dans les six dernières heures » renvoyait toutes les URL du fichier. Utilisé naïvement, ce lastmod déclencherait une re-récupération de tout, à chaque fois.
Second échec : aucun lastmod du tout. Nous avons lu le sitemap d’une vaste archive de documents techniques. Elle listait 10 236 URL, et aucune ne portait de lastmod. C’est une excellente source de découverte, mais d’aucune aide pour décider quoi re-récupérer.
C’est pourquoi les propres consignes de Google indiquent qu’il n’utilise lastmod que « si c’est de façon cohérente et vérifiable (par exemple en comparant à la dernière modification de la page) exact », et pourquoi vous devriez appliquer le même test vous-même. Avant de planifier sur le lastmod d’un site :
- Vérifiez la répartition. Si la plupart des entrées partagent un même horodatage, ou si les valeurs suivent l’heure de génération du fichier, le champ ne décrit pas les changements de page.
- Échantillonnez et comparez. Récupérez un échantillon de pages et comparez
lastmodavec un signal indépendant, comme ledateModifiedpropre à la page dans les données structurées ou une empreinte de contenu. La façon d’extrairedateModifiedest traitée dans stop parsing HTML, et la façon de comparer le contenu sans se noyer dans le bruit dans change detection at scale. - Notez le site. Enregistrez, par site, la fréquence à laquelle
lastmoda changé quand le contenu a changé, et la fréquence à laquelle le contenu a changé quandlastmodn’a pas changé. N’utilisezlastmodpour la planification que sur les sites qui réussissent ce test, et continuez à vérifier, car le générateur de sitemap d’un site peut changer sans préavis.
La place des sitemaps dans un pipeline de collecte
Les sitemaps sont les plus utiles en première étape, pas comme seule étape :
- Découverte. Un sitemap donne directement l’inventaire, y compris les pages mal reliées par des liens. Pour les sites de catalogue et de contenu, c’est souvent la liste d’URL la plus complète disponible.
- Segmentation. Les sitemaps sont couramment découpés par type de contenu ou par section, comme les produits, catégories, articles et vidéos. Ce découpage indique comment un site est organisé avant même de récupérer une seule page.
- Collecte incrémentale, sur les sites dont le
lastmodpasse les vérifications ci-dessus, et via les sitemaps d’actualités pour les articles récents. - Vérifications de couverture. Comparer ce que votre crawler a trouvé avec ce que liste le sitemap montre ce qui manque.
Conservez le crawling par liens comme filet de sécurité. Les sitemaps peuvent être obsolètes, incomplets, ou délibérément limités à ce qu’un site souhaite voir indexé. Et respectez le robots.txt du site pour les pages elles-mêmes : qu’une URL apparaisse dans un sitemap est une invitation aux moteurs de recherche à l’indexer, pas une renonciation à tout autre demande du site, comme traité dans robots.txt, AI opt-outs and reservation signals.
Utilisés ainsi, les sitemaps réduisent le budget de récupération aux deux endroits où il est habituellement gaspillé : naviguer pour trouver des pages, et re-récupérer des pages qui n’ont pas changé. La seconde économie dépend entièrement de la fiabilité de lastmod, c’est pourquoi cost-aware crawl scheduling devrait traiter un lastmod non vérifié comme un indice, pas comme un fait.
L’essentiel
Les sitemaps sont l’inventaire d’URL le moins coûteux du web : un site qui vous indique, dans un format standard, ce qu’il souhaite voir trouvé. Lisez-les depuis le robots.txt, gérez le gzip et les index imbriqués, plafonnez ce que vous récupérez, et utilisez-les d’abord pour la découverte.
Traitez ensuite lastmod comme le fait Google : utile seulement quand il a été démontré exact pour ce site. Sur un site que nous avons vérifié, ce n’était que l’heure de génération du fichier. Sur un autre, il n’existait pas. Sur un site où il tient la route, il peut réduire considérablement les re-récupérations. Le seul moyen de savoir à quel type de site on a affaire est de vérifier.
Sources et références
- Sitemaps.org, Sitemaps XML format.
- Google Search Central, Build and submit a sitemap.
- Sitemaps lus par Shifter le 29 septembre 2026 à l’aide du code ci-dessus.