Scraping

Détection des changements à grande échelle : comparer des pages web sans se noyer dans le bruit

Les pages changent à chaque chargement : publicités, horodatages, jetons. Comment distinguer les vrais changements du bruit grâce à la normalisation, aux diffs au niveau des champs et au simhash, avec du code testé.

Chris Collins

Chris Collins

27 septembre 2026 · 11 min de lecture

Chaque tâche de surveillance finit par poser la même question : est-ce que cette page a changé ? Cela ressemble à une comparaison de hachage. Ce n’en est pas une. Les pages modernes changent à chaque chargement, avec des publicités tournantes, des horodatages, des blocs de recommandation, des jetons de session et des compteurs en direct, si bien qu’une comparaison naïve signale un changement à chaque fois et le canal d’alerte se remplit de bruit jusqu’à ce que tout le monde le désactive. L’échec inverse est plus silencieux et pire : un pipeline tellement calibré pour ignorer le bruit qu’il rate la baisse de prix ou le certificat supprimé qu’il était censé détecter.

Ce guide explique comment détecter les changements réels à grande échelle : comparer des champs plutôt que des pages, normaliser ce qu’on ne peut pas éviter de comparer, mesurer à quel point une page a changé plutôt que si elle a changé, et acheminer chaque type de changement vers le bon endroit.

Points clés

  • La comparaison brute d’octets est inutile pour la plupart des sites. Nous avons récupéré la page d’accueil d’un site d’actualités deux fois, à 45 secondes d’intervalle : les octets différaient, et même le texte nettoyé différait.
  • Comparez des champs, pas des pages, chaque fois que possible. Un prix, un titre ou un statut de stock a changé ou n’a pas changé.
  • Là où vous devez comparer des pages entières, normalisez d’abord, puis mesurez la similarité. Simhash, la technique d’empreinte digitale décrite par Google pour la détection de quasi-doublons parmi 8 milliards de pages, transforme “est-ce que ça a changé ?” en “à quel point est-ce que ça a changé ?”
  • Classez chaque changement : changement de champ, changement de contenu ou bruit. Chacun mérite une réponse différente.
  • Ajustez par site et par type de page. Un seuil adapté à une page produit est inadapté à une page d’accueil d’actualités.

Pourquoi la comparaison naïve échoue

Pour voir le problème concrètement, nous avons récupéré la page d’accueil internationale d’un grand site d’actualités deux fois, à 45 secondes d’intervalle. Le HTML brut différait, comme attendu. Plus intéressant : après avoir retiré les scripts, les styles et le balisage, et supprimé les horodatages et les jetons, le texte visible différait encore. Les pages en direct se mettent à jour continuellement. Un moniteur qui alerte sur toute différence aurait alerté sur cette page à chaque exécution.

Les sources de bruit sont prévisibles :

BruitExempleCorrectif typique
Scripts et données intégrésCharges analytiques, état JSON, jetons CSRFRetirer les blocs script et style avant la comparaison
Texte basé sur le temps”Mis à jour il y a 3 minutes”, heures d’horloge, datesSupprimer avec des motifs, ou comparer des champs qui les excluent
Modules rotatifsPublicités, “tendances actuelles”, recommandationsComparer uniquement la région ou les champs qui vous intéressent
Personnalisation et expérimentationsVariantes de test A/B, blocs spécifiques à la localisationCollecter depuis un point d’observation fixe avec des paramètres cohérents
OrdonnancementListes qui se mélangent à chaque chargementTrier avant de comparer

Une partie du bruit est en réalité une différence liée à qui a fait la demande. Une page chargée depuis l’Allemagne peut différer de la même page chargée depuis les États-Unis pour des raisons qui n’ont rien à voir avec un changement. Gardez le point d’observation fixe pour chaque page surveillée, de sorte que la seule chose qui varie entre les exécutions soit le temps. Avec une passerelle résidentielle, cela signifie fixer le pays, par exemple customer-USERNAME-country-de, pour chaque exécution de cette tâche.

Principe 1 : comparer des champs, pas des pages

Le détecteur de changement le plus fiable ne fait pas de diff sur les pages du tout. Il extrait les champs qui comptent, comme le prix, la disponibilité, le titre, une liste de certificats ou une adresse, et compare ces valeurs. Un champ a changé ou n’a pas changé, et le bruit ailleurs sur la page est sans importance.

Les données structurées facilitent cela plus qu’il n’y paraît. De nombreuses pages publient leurs champs clés sous forme de JSON-LD, ce qui est bien plus stable que la mise en page qui l’entoure ; l’extraction de ces données est couverte dans arrêtez de parser le HTML. Lorsque les champs proviennent plutôt de sélecteurs, comparez les valeurs extraites, jamais le HTML qui les entoure.

La comparaison de champs rend aussi les alertes utiles. “Le prix est passé de 89,00 à 79,00” est actionnable. “La page a changé” ne l’est pas.

Principe 2 : normaliser ce que vous devez comparer

Certaines surveillances portent vraiment sur des pages entières : conditions d’utilisation, page “à propos” d’un fournisseur, déclaration de durabilité, page de politique. Pour celles-ci, retirez ce qui ne compte jamais avant de comparer :

  • Retirez les blocs sans contenu : scripts, styles, modèles, SVG en ligne.
  • Ne gardez que le texte visible, avec les espaces réduits et la casse uniformisée.
  • Retirez les fragments volatils : heures d’horloge, dates ISO, temps relatifs, jetons et identifiants hexadécimaux longs.
  • Restreignez à une région lorsqu’une page a une zone de contenu principal stable, comme le corps de l’article ou l’élément principal.

La normalisation retire une grande part du bruit. Elle ne le retire pas entièrement, ce qui explique pourquoi l’étape suivante compte.

Principe 3 : mesurer combien, pas si

Plutôt que de demander si le texte normalisé est identique, demandez à quel point il est similaire. Simhash est un bon outil pour cela. Il réduit un document à une empreinte de 64 bits avec une propriété utile : des documents similaires obtiennent des empreintes qui ne diffèrent que sur quelques positions de bits. Google a décrit son utilisation pour la détection de quasi-doublons dans “Detecting Near-Duplicates for Web Crawling” (WWW 2007), où les auteurs ont validé que “for a repository of 8B web-pages, 64-bit simhash fingerprints and k = 3 are reasonable”, ce qui signifie que des pages dont les empreintes diffèrent d’au plus trois bits pourraient être considérées comme des quasi-doublons.

Cela transforme la détection de changement en une question de distance. Dans notre test, les deux récupérations de la page d’accueil d’actualités, à 45 secondes d’intervalle, se sont révélées éloignées de 2 bits : en dessous du seuil, donc du bruit. La même page d’accueil comparée à un article sans rapport s’est révélée éloignée de 34 bits : un contenu clairement différent.

import hashlib
import re

VOLATILE = [
    r"\b\d{1,2}:\d{2}(?::\d{2})?\s?(?:am|pm|AM|PM)?\b",          # clock times
    r"\b\d{4}-\d{2}-\d{2}(?:T[\d:.]+Z?)?\b",                      # ISO dates
    r"\b\d+\s+(?:second|minute|hour|day)s?\s+ago\b",              # relative times
    r"\b(?:csrf|nonce|token|session|sid)[\w-]*[=:]\s*[\w-]+",      # tokens
    r"\b[0-9a-f]{24,}\b",                                         # long hex ids
]


def normalise(html):
    """Visible text only, with volatile fragments removed."""
    html = re.sub(r"(?is)<(script|style|noscript|svg|template)\b.*?</\1>", " ", html)
    text = re.sub(r"(?s)<[^>]+>", " ", html)
    for pattern in VOLATILE:
        text = re.sub(pattern, " ", text, flags=re.I)
    return re.sub(r"\s+", " ", text).strip().lower()


def simhash(text, bits=64):
    """Charikar-style simhash over word 3-grams."""
    words = text.split()
    grams = [" ".join(words[i:i + 3]) for i in range(max(1, len(words) - 2))]
    weights = [0] * bits
    for gram in grams:
        h = int.from_bytes(hashlib.blake2b(gram.encode(), digest_size=8).digest(), "big")
        for i in range(bits):
            weights[i] += 1 if h >> i & 1 else -1
    return sum(1 << i for i in range(bits) if weights[i] > 0)


def distance(a, b):
    return bin(a ^ b).count("1")


def compare(old_html, new_html, old_fields=None, new_fields=None, threshold=3):
    """Classify a change as none, noise, content or field-level."""
    old_fields, new_fields = old_fields or {}, new_fields or {}
    field_changes = {k: (old_fields.get(k), new_fields.get(k))
                     for k in set(old_fields) | set(new_fields)
                     if old_fields.get(k) != new_fields.get(k)}
    if field_changes:
        return {"kind": "field", "changes": field_changes}
    if old_html == new_html:
        return {"kind": "none"}
    d = distance(simhash(normalise(old_html)), simhash(normalise(new_html)))
    return {"kind": "content" if d > threshold else "noise", "distance": d}

Traitez le seuil comme un point de départ, pas comme une constante. Le chiffre de WWW 2007 a été choisi pour trouver des doublons parmi des milliards de pages, pas pour surveiller une page dans le temps. Calibrez-le par type de page : récupérez chaque page surveillée plusieurs fois de suite, à un moment où rien de significatif ne devrait changer, et fixez le seuil juste au-dessus des distances observées. Les pages courtes demandent plus de prudence, car quelques mots modifiés déplacent l’empreinte d’un petit document davantage que celle d’un document long.

Principe 4 : classer, puis acheminer

Un détecteur qui renvoie seulement “changé” reporte le vrai travail sur celui qui lit l’alerte. Renvoyez un type, et acheminez en fonction de celui-ci :

TypeSignificationOù cela va
fieldUne valeur que vous suivez a changéDirectement dans le jeu de données et, si c’est important, une alerte
contentLe fond de la page a changé au-delà du bruitUne file d’examen humain, avec un diff textuel joint
noiseLa page a bougé, mais dans les limites de la variation normaleEnregistré pour calibration, jamais alerté
noneIdentique octet pour octetRien

Deux raffinements sont rentables. Conservez l’instantané précédent et un diff textuel lisible pour chaque changement de type content, afin qu’un relecteur puisse en juger en quelques secondes. Et enregistrez le taux de chaque type par site : un site dont la distance de bruit augmente progressivement sur plusieurs semaines change ses modèles, et un site qui ne produit soudainement plus aucun changement pourrait vous servir une page obsolète ou bloquée, un mode d’échec couvert dans le taux d’échec silencieux.

Passer à l’échelle

La détection de changement à grande échelle est surtout un problème de stockage et de planification.

  • Stockez des empreintes et des champs, pas des pages complètes, pour la plupart des exécutions. Une empreinte de 64 bits et une poignée de champs sont minuscules. Ne gardez des instantanés complets que lorsqu’un changement est détecté, ou selon un calendrier plus lent pour l’audit.
  • Revisitez selon le changement attendu. Les pages qui changent rarement n’ont pas besoin de vérifications horaires. La planification de crawl sensible aux coûts explique comment dépenser un budget de récupération là où le changement est probable, et chaque résultat none ou noise est une preuve pour ce modèle.
  • Utilisez d’abord les signaux bon marché. Là où un site envoie des en-têtes ETag ou Last-Modified fiables, une requête conditionnelle qui renvoie 304 Not Modified répond à la question pour presque aucune bande passante.
  • Surveillez le surveillant. Des pages canaris avec des motifs de changement connus vous disent si le détecteur lui-même fonctionne encore.

Où cela est utilisé

Le même mécanisme sous-tend des tâches très différentes : la surveillance des prix et des stocks, où les changements de champs sont tout l’enjeu, comme dans construire un flux de prix concurrentiel en temps réel ; la surveillance des fournisseurs et de la conformité, où les changements de contenu de page entière comptent, comme dans surveiller l’empreinte publique de vos fournisseurs et vérifier les allégations ESG ; et la préservation de preuves lorsqu’un changement a une portée juridique.

En résumé

“Est-ce que cette page a changé ?” est la mauvaise question pour le web moderne, car la réponse est presque toujours oui. Les questions utiles sont “est-ce qu’un champ qui m’intéresse a changé ?” et, là où vous devez comparer des pages entières, “est-ce que le fond a changé au-delà de la variation normale de cette page ?”

Comparez des champs chaque fois que possible. Normalisez ce que vous ne pouvez pas éviter de comparer, mesurez la similarité plutôt que l’égalité, calibrez les seuils par type de page, et acheminez chaque type de changement vers l’endroit qui peut agir dessus. Le résultat est un flux de changements auquel les gens font confiance, ce qui est le seul type qui soit lu.

Sources et références

Prêt à commencer ?

Essayez les proxies résidentiels de Shifter, 205M+ IPs, 195+ pays, à partir de 0,75 $/GB.

Commencer