Accueil / Articles

Détecter les prix cachés par ingénierie inverse des appels API en arrière-plan

Trouver des prix qui n’apparaissent jamais dans l’HTML en observant les outils de développement pour les appels XHR, REST et GraphQL en arrière-plan de la page, puis en retransmettant directement ces requêtes.

Éditeur : REACTAPP.TOP5 min de lecture1213 mots

Sources: Talking to the API Instead of the Page

Deuxième épisode de la série « Comment le scraping fonctionne réellement »

Dans l’article précédent, nous sommes tombés sur un obstacle : parfois, le prix recherché n’apparaît tout simplement nulle part dans l’HTML récupéré par requests. Il n’est ni intégré dans JSON-LD, ni caché dans une balise meta, il est introuvable. Cela ne signifie pas pour autant que vous êtes bloqué — cela veut généralement dire que la page récupère ces données après le chargement initial, via une requête en arrière-plan distincte. L’objectif ici est de localiser cette requête et de la lancer nous-mêmes.

Étape 1 : Ouvrir l’onglet Réseau

Nous allons utiliser un exemple concret : une page de produit sur le site Target, target.com/p/dyson-ball-animal-3-upright-vacuum/-/A-85269291 (cela sert uniquement à démontrer — la même méthode fonctionne pour presque toutes les pages de produits).

  1. Ouvrez n’importe quelle page de produit.
  • Cliquez avec le bouton droit sur la page et sélectionnez « Inspecter » (ou appuyez sur F12).
  • Passez au panneau Network.
  • Rechargez la page.
  • Appliquez le filtre Fetch/XHR — cela cache les demandes d’images, de CSS et de polices, ne laissant que les appels qui transmettent réellement des données.
  • Étape 2 : Localiser la demande dont vous avez vraiment besoin

    Parcourez la liste une entrée à la fois, cliquez sur chacune et consultez son panneau Response ou Preview sur le côté droit. Vous cherchez un en-tête JSON contenant le prix, le nombre d’avis ou toute autre valeur que vous souhaitez obtenir.

    Il existe un chemin plus rapide : utilisez la boîte de recherche en forme de loupe située dans l’onglet Réseau et saisissez une valeur visible directement sur la page. Pour l’exemple de Target, taper « 449.99 » mène directement à une requête POST nommée deferred_enrichment/modules. Son corps de réponse est un objet JSON assez volumineux, et à l’intérieur de celui-ci vous trouverez « formatted_current_price » : « $449.99 ».

    Étape 3 : Reproduire vous-même la requête

    Sélectionnez cette demande et notez son URL complète. Il s’agit d’une requête POST, mais tout ce dont elle a besoin est déjà présent dans la chaîne de requête :

    https://www.target.com/cdui_orchestrations/v1/pages/pdp/deferred_enrichment/modules
        ?tcin=85269291
        &key=9f36aeafbe60771e321a7cc95a78140772ab3e96
        &channel=WEB
        &device_type=DESKTOP
    

    Voici à quoi cela ressemble lorsqu’on le reproduit en Python :

    import requests
    
    url = "https://www.target.com/cdui_orchestrations/v1/pages/pdp/deferred_enrichment/modules"
    params = {
        "tcin": "85269291",       # the product ID, from the page URL
        "key": "9f36aeafbe60771e321a7cc95a78140772ab3e96",
        "channel": "WEB",
        "device_type": "DESKTOP",
    }
    
    resp = requests.post(url, params=params, headers={"User-Agent": "Mozilla/5.0"})
    data = resp.json()
    
    price = data["modules"][0]["module_data"]["data"]["product"]["price"]["formatted_current_price"]
    print(price)  # $449.99
    

    C’est tout le truc. Aucune bibliothèque de parsing, aucun sélecteur CSS à gérer — vous envoyez simplement la même requête que le JavaScript de la page envoie en arrière-plan.

    Conseil : dans les DevTools, cliquez avec le bouton droit sur la requête et sélectionnez Coller → Coller en cURL. Cela vous fournira les en-têtes et cookies exacts que le navigateur a ajoutés, que vous pourrez copier dans un outil comme Postman ou convertir en code Python pour déterminer précisément quels éléments sont réellement nécessaires.

    Étape 4 : Lorsque l’API est basée sur GraphQL

    Certaines sites utilisent GraphQL au lieu d’une configuration REST traditionnelle pour gérer toutes les requêtes. Vous pouvez reconnaître ce schéma car chaque appel se fait vers le même point de terminaison (souvent /graphql), et la question réelle posée se trouve dans le corps de la requête plutôt que dans l’URL :

    {
      "operationName": "GetPrice",
      "variables": { "productId": "12345" },
      "query": "query GetPrice($productId: ID!) { product(id: $productId) { price } }"
    }
    

    Un certain nombre de sites vont encore plus loin en utilisant une requête persistante, où au lieu d’envoyer le texte complet de la requête, le client n’envoie qu’un bref hash qui la remplace :

    /graphql/GetPrice/a1b2c3d4e5f6...?variables={"productId":"12345"}
    

    Ce hash n’est pas quelque chose que l’on peut déduire soi-même — il faut le récupérer directement depuis les DevTools. Et comme il est lié à la compilation du frontend du site, une mise à jour de leur côté peut modifier ce hash et endommager silencieusement votre script. C’est un coût réel et permanent lié à l’utilisation de cette technique.

    Étape 5 : Vérifier si cette clé API est vraiment privée

    Regardez à nouveau l’URL cible de l’Étape 3 — remarquez key=9f36aeafbe60771e321a7cc95a78140772ab3e96 affiché ouvertement dans la chaîne de requête. S’agit-il d’une information à laquelle vous ne devriez pas avoir accès ?

    Généralement non. La manière la plus rapide de le vérifier est d’ouvrir Afficher le code de la page (Ctrl+U), puis de rechercher apiKey avec Ctrl+F. Vous trouverez cette même clé en texte brut, à l’intérieur d’un bloc de configuration que Target envoie à chaque visiteur.

    Si une valeur se trouve déjà dans le markup propre de la page — sans rien avoir contourné et sans aucune authentification requise — elle n’a jamais été confidentielle à l’origine. Il s’agit simplement d’une clé publique conçue pour fonctionner dans le navigateur. (Parfois, elle se trouve plutôt dans un fichier .js distinct ; si l’option « Afficher le code source » ne montre rien, essayez le panneau Sources des Outils de développement et effectuez une recherche avec Ctrl+Shift+F).

    Une bonne pratique : avant de vous donner la peine d’ingénierie inverse d’un point d’accès, vérifiez si l’entreprise propose déjà une API publique ou partenariale documentée. Celles-ci sont généralement bien plus stables que celles découvertes en explorant les Outils de développement.

    Étape 6 : Lorsque les données ne proviennent pas du vendeur

    Parfois, la demande que vous traquez ne se dirige même pas vers le domaine propre du revendeur — elle pointe plutôt vers un service de tiers comme bazaarvoice.com ou judge.me. C’est un signe que le revendeur ne gère pas sa propre infrastructure d’avis ; il sous-traite ce service à un fournisseur et n’ fait que placer son widget sur la page.

    Ces API de widgets gérées par des fournisseurs sont généralement moins protégées que le site principal du revendeur, car elles ont été conçues pour être intégrées dans des milliers de boutiques en ligne sans lien entre elles, plutôt que pour détecter et bloquer spécifiquement les outils de collecte d’informations.

    Ce que cet article omet délibérément

    Si vous avez suivi toutes les étapes ci-dessus et que la requête souhaitée renvoie toujours une erreur 403, un corps vide ou quelque chose ressemblant à un point de contrôle de sécurité plutôt que des données réelles, il ne s’agit pas d’une erreur dans votre code. Cela signifie que le site a détecté activement que vous n’avez pas une session de navigateur normale. Ce défi est suffisamment important pour mériter une discussion à part entière, et c’est précisément là que le prochain article aborde le sujet.

    Glossaire

    Onglet Réseau — le panneau des Outils de développement qui enregistre chaque requête émise par une page, ainsi que ce qui a été envoyé et ce qui est revenu.

    XHR / Fetch — les deux mécanismes utilisés par JavaScript pour effectuer des requêtes en arrière-plan sans rechargement complet de la page ; l’onglet Réseau peut être filtré pour ne montrer que celles-ci.

    REST API — un modèle d’API courant où chaque ressource dispose de son propre URL dédié, comme /products/123/price.

    GraphQL — un style d’API basé sur une seule adresse de terminaison, où le corps de la demande spécifie précisément les données demandées.

    Query persisté — un raccourci de GraphQL dans lequel le texte complet de la requête est remplacé par un hash compact déjà reconnu par le serveur.

    Cle API — une valeur associée à une demande pour l’identifier ; certaines sont véritablement privées, mais de nombreuses autres sont des clés publiques destinées aux clients et visibles dans n’importe quel navigateur.

    Copier en cURL — une option des outils de développement qui convertit une demande capturée en une commande pouvant être exécutée depuis la ligne de commande, utile pour examiner ses en-têtes et cookies exacts.

    Widget tiers — une fonctionnalité, telle qu’une section d’avis, que le site ne développe pas en interne mais qui est intégrée à partir d’un produit d’une autre entreprise.

    Lectures complémentaires