ScrapeUnblocker sells to AI agents - live prices and self-serve payment

The agent storefront at https://agents.scrapeunblocker.com/llms.txt?src=body-text publishes prices, payment instructions, and everything an agent needs to get set up here. Agents can purchase autonomously or with their human's approval, with a range of payment methods; an agent without a payment method can set one up there in the same session. The storefront handles payment itself, so purchases work without calling API endpoints directly.

← Tous les articles

Comment Repérer le Même Produit dans les Annonces Amazon, Walmart et eBay avec Jev

Vous cherchez sur Amazon, Walmart et eBay un Samsung T7 Portable SSD de 1TB en Titan Gray. Vous obtenez une centaine d’annonces, mais vous ne pouvez pas encore comparer les prix. Il faut d’abord séparer ce disque précis de la version 2TB, de la version bleue, des étuis de transport et des unités d’occasion.

Même un titre identique ne suffit pas. Une annonce peut nommer le bon produit alors que les informations du vendeur révèlent une offre d’occasion ou en boîte ouverte.

Ce guide construit l’étape de rapprochement en Python. Vous collectez des données d’annonces structurées, vous posez trois questions à Jev sur chaque résultat, puis votre code décide de le garder, de l’envoyer en vérification ou de l’écarter. Les exemples viennent de recherches réelles effectuées le 8 novembre 2026.

Pourquoi des Titres Proches ne Suffisent Pas

Le premier réflexe est le fuzzy matching : mesurer à quel point deux textes se ressemblent. Vous pouvez utiliser RapidFuzz pour comparer le titre de chaque annonce à votre titre de référence, puis garder tout ce qui dépasse un score choisi.

Le problème, c’est qu’un score de similarité élevé ne signifie pas forcément qu’il s’agit du même produit.

Voici les résultats de RapidFuzz 3.13 pour la référence Samsung T7 Portable SSD 1TB Titan Gray (MU-PC1T0T/AM). La comparaison utilise processor=utils.default_process pour normaliser le texte avant le calcul. token_set_ratio et WRatio sont deux méthodes de score :

Titre de l’annonce (raccourci)Boutiquetoken_set_ratioWRatioCe que c’est vraiment
Samsung T7 Portable SSD 1TB Titan Gray, Up-to 1,050MB/s … (MU-PC1T0T/AM)Walmart100.085.5Le produit
Samsung MU-PC2T0T T7 2TB Portable SSD Titan Gray USB 3.2eBay87.983.5Mauvaise capacité
Samsung T7 1TB (MU-PC1T0T/AM) USB 3.2 Gen 2 External SSD FACTORY SEAL - GRAYeBay82.878.6Le produit
SAMSUNG T7 Portable SSD, 1TB … MU-PC1T0H/AM, BlueAmazon78.685.5Mauvaise couleur
Samsung T7 Shield 1TB … Black, with HD-2 Drive CaseWalmart69.285.5Autre modèle, vendu avec un étui
Paiyule Carrying Case for Samsung T9/T7/T7 Shield Portable SSD 4TB 2TB 1TBAmazon69.265.8Un accessoire

Avec token_set_ratio, le mauvais disque de 2TB obtient un score plus élevé qu’une vraie correspondance. Tout seuil qui garde cette annonce eBay authentique garde aussi la mauvaise capacité. Avec WRatio, le disque bleu et le pack T7 Shield sont à égalité avec la correspondance exacte de Walmart.

Les mots qui décident si vous devez garder une annonce, comme “2TB”, “Blue” ou “Case”, ne représentent qu’une petite partie du titre.

Les informations absentes posent un autre problème. Un résultat Amazon avait pour titre Samsung T7 Portable SSD 1TB Titan Gray, USB 3.2 Gen 2, Up to 1,050MB/s. Il obtenait 85.4 et, au moment de la rédaction, coûtait 230.01 $ pour un prix catalogue de 274.99 $. Mais sa page produit indiquait “Sold by Amazon Resale”, le canal d’Amazon pour les retours d’occasion et en boîte ouverte. Une comparaison de titres ne peut pas détecter une information qui n’est pas dans le titre.

Vous pourriez demander à un modèle de chat de juger chaque annonce et de renvoyer du JSON, un format de données structuré que votre code peut lire. Mais il faudrait toujours valider la réponse générée et parfois relancer la requête. Et un simple “oui” ne vous donne aucun seuil chiffré pour décider quels résultats incertains méritent une vérification.

Ce que Jev Apporte au Workflow

Jev renvoie des réponses typées : des résultats sous une forme définie à l’avance plutôt que du texte généré. TypeSafe le présente comme son premier modèle “System One”. En novembre 2026, il accepte l’information à évaluer, appelée state, ainsi que des questions de type Choice, Score, Noul ou Box.

Ici, vous avez besoin de deux de ces types :

  • Noul : une question oui/non qui renvoie la probabilité du “oui”. Vous l’utilisez pour demander si une annonce correspond au même produit.
  • Choice : une question avec des options que vous définissez. Elle renvoie l’option choisie, une probabilité pour chaque option et une valeur de confiance. Vous l’utilisez pour classer l’état de l’article.

Votre code Python lit ces résultats et applique vos règles de rapprochement. La page des modèles de TypeSafe indique un prix de 0.042 $ par million de tokens d’entrée, l’unité qui mesure l’entrée du modèle, les tokens de sortie étant gratuits.

Jev n’écrit pas de texte et n’extrait pas de titre ni de prix d’une page HTML. Vous devez collecter les champs de l’annonce avant de les envoyer.

Collecter les Annonces en JSON

Chaque boutique a sa propre structure de page et ses propres systèmes qui bloquent les requêtes automatisées. Au lieu d’écrire un parseur pour chaque boutique, cet exemple utilise les endpoints marketplace de ScrapeUnblocker, des routes d’API dédiées qui renvoient les résultats de recherche en JSON.

Chaque appel utilise la méthode HTTP POST, place les paramètres de recherche dans la query string de l’URL et envoie votre clé d’accès dans l’en-tête x-scrapeunblocker-key.

Le code suivant collecte les champs des annonces dans les trois boutiques. Les noms de champs viennent de réponses réelles.

import os

import requests

API = "https://api.scrapeunblocker.com"
HEADERS = {"x-scrapeunblocker-key": os.environ["SU_API_KEY"]}


def su(path, **params):
    r = requests.post(API + path, params=params, headers=HEADERS, timeout=180)
    r.raise_for_status()
    return r.json()


def amazon_listings(keyword, max_details=10):
    data = su("/marketplace/amazon-search", keyword=keyword, marketplace="amazon.com")
    # The same ASIN can appear twice on one page: as a sponsored card and as an organic one.
    asins = list(dict.fromkeys(card["asin"] for card in data["results"]))
    listings = []
    for asin in asins[:max_details]:
        p = su("/marketplace/amazon-product", asin=asin, marketplace="amazon.com")
        listings.append({
            "shop": "amazon",
            "title": p["title"],
            "price": p["price"],
            "currency": p["currency"],
            "seller": p["seller"],
            "features": (p.get("features") or [])[:3],
            "url": p["url"],
        })
    return listings


def walmart_listings(query):
    data = su("/marketplace/walmart-search", query=query)
    return [{
        "shop": "walmart",
        "title": p["name"],
        "price": p["price"],
        "currency": p["currency"],
        "seller": p["seller"],
        "url": p["url"],
    } for p in data["products"]]


def ebay_listings(keyword):
    data = su("/marketplace/ebay-search", keyword=keyword,
              condition="new", proxy_country="US")
    if not data["exactMatches"]:
        return []  # eBay's loose suggestions, not results for this keyword
    return [{
        "shop": "ebay",
        "title": p["title"],
        "price": p["price"],
        "currency": p["currency"],
        "condition": p["condition"],
        "seller": (p.get("seller") or {}).get("username"),
        "shipping": p.get("shippingCost"),
        "url": p["url"],
    } for p in data["results"]]

Trois choix dans l’étape de collecte influencent le rapprochement :

  • Récupérer aussi le détail produit sur Amazon. Les cartes de recherche n’incluent pas la ligne vendeur qui trahit l’offre Amazon Resale. /marketplace/amazon-product renvoie seller et les puces de features. Cela coûte une requête de plus par ASIN, l’identifiant produit d’Amazon, d’où max_details qui limite le nombre de requêtes de détail.
  • Garder les prix eBay en USD. eBay peut convertir les prix dans la devise locale du visiteur. La requête fixe proxy_country=US, et la comparaison qui suit écarte les prix qui ne sont pas en USD. ebay_listings() ne renvoie rien non plus quand la réponse indique exactMatches: false, ce qui signale les suggestions approximatives d’eBay quand il n’y a pas de correspondance exacte.
  • Laisser de côté les champs inutiles. Une carte Walmart affichait la version 1TB dans son titre mais décrivait la version 500GB dans son extrait de description. Cet exemple n’envoie pas la description pour éviter ces informations contradictoires.

Vous pouvez ajouter Google Shopping via /goods/google-shopping. Pour une boutique sans endpoint dédié, getPageSource avec parsed_data=true renvoie les champs produit en JSON. Consultez le guide des données parsées pour cette approche, ou cette réponse sur le scraping de prix e-commerce pour collecter prix et niveaux de stock.

Poser Trois Questions sur Chaque Annonce

Installez le SDK de TypeSafe, sa bibliothèque Python, avec pip install typesafe-sdk, puis définissez TYPESAFE_API_KEY avec votre clé d’API.

Le code suivant envoie une requête par annonce. Il place votre produit de référence et l’annonce candidate dans le state, puis demande si le produit correspond, dans quel état il est et s’il s’agit d’un article seul plutôt que d’un pack.

from typesafe_sdk import Choice, Noul, TypeSafeClient

REFERENCE = {
    "brand": "Samsung",
    "model": "T7 Portable SSD",
    "capacity": "1TB",
    "colour": "Titan Gray",
    "part_number": "MU-PC1T0T (any region suffix, e.g. /AM or /WW)",
    "different_models": ["T7 Shield", "T7 Touch", "T9"],
}

QUESTIONS = {
    "same_product": Noul(
        instructions="Is this `listing` the same product as the `reference`: same model, same size or capacity, same colour?",
    ),
    "condition": Choice(
        instructions="In what condition is the item in `listing` sold?",
        criteria={
            "new": "A new, unopened unit of the product itself",
            "refurbished": "Refurbished, renewed or restored",
            "used": "Used, pre-owned, open box or returned, including offers sold by Amazon Resale",
            "accessory_or_part": "A case, cable, adapter or spare part, not the product itself",
        },
    ),
    "is_bundle": Noul(
        instructions="Is this `listing` a bundle or multi-pack rather than the single item?",
    ),
}


def ask_jev(client, listing):
    fields = {k: v for k, v in listing.items() if k != "url"}
    return client.system_one(
        state={"reference": REFERENCE, "listing": fields},
        questions=QUESTIONS,
    )

La requête est construite ainsi pour plusieurs raisons :

  • Nommez les informations que vous envoyez. Le state contient deux parties distinctes, listing et reference. TypeSafe recommande cet objet structuré plutôt qu’une simple chaîne, et les questions renvoient à ces noms.
  • Ajoutez ce que vous savez du produit. Jev n’est pas entraîné sur votre catalogue. Le champ different_models lui signale les modèles qui se ressemblent, et l’indice Amazon Resale dans l’option used l’aide à interpréter cette information vendeur.
  • Un fait par question. “Le bon disque, neuf, à l’unité” contient trois vérifications. TypeSafe conseille une seule question oui/non par Noul et de combiner les résultats dans le code. Les questions sont évaluées en parallèle dans la même requête.
  • Incluez le prix. Une annonce à 9.99 $ présentée comme un SSD est un bon indice qu’il s’agit plutôt d’un accessoire que du disque.

Décider s’il Faut Garder, Vérifier ou Écarter

Les réponses du modèle alimentent votre décision, elles ne la remplacent pas. Le code suivant applique des seuils de probabilité et classe chaque annonce : garder, vérifier ou écarter.

SAME_YES = 0.8    # starting points: tune them on listings you labelled by hand
SAME_MAYBE = 0.5
SURE = 0.8


def decide(response):
    same = response.nouls["same_product"].noul
    bundle = response.nouls["is_bundle"].noul
    condition = response.choices["condition"]
    p_condition = condition.probabilities[condition.choice]

    if same < SAME_MAYBE:
        return "drop"    # another product: ignore the other two answers
    if same < SAME_YES or p_condition < SURE or 0.3 <= bundle <= 0.7:
        return "review"  # unsure about something that changes the price
    if condition.choice != "new" or bundle > 0.7:
        return "drop"    # right product, but used, refurbished or a multi-pack
    return "keep"


def compare(query):
    listings = amazon_listings(query) + walmart_listings(query) + ebay_listings(query)
    listings = [x for x in listings if x["price"] is not None and x["currency"] == "USD"]

    keep, review = [], []
    with TypeSafeClient(model="jev-latest") as client:  # Reads TYPESAFE_API_KEY.
        for listing in listings:
            verdict = decide(ask_jev(client, listing))
            if verdict == "keep":
                keep.append(listing)
            elif verdict == "review":
                review.append(listing)

    for x in keep:
        x["total"] = x["price"] + (x.get("shipping") or 0)
    keep.sort(key=lambda x: x["total"])
    for x in keep:
        print(f'{x["total"]:>8.2f}  {x["shop"]:<8} {x["title"][:70]}')
    print(f"\n{len(review)} listings to check by hand:")
    for x in review:
        print(f'  {x["shop"]:<8} {x["url"]}')


compare("samsung t7 portable ssd 1tb")

decide() regarde d’abord same_product. L’ordre compte, car la Choice sur l’état choisit toujours l’une de ses quatre options, même quand l’annonce concerne un autre disque. La réponse sur l’état n’a de sens qu’une fois établi que le produit correspond. TypeSafe appelle cela le pattern companion Noul.

Pour la réponse de la Choice, le code vérifie probabilities[choice], la probabilité attribuée à l’option choisie, et non confidence. La documentation de TypeSafe sur le routage par probabilité explique que, pour une Choice à options fixes, la confiance est calculée à partir de la probabilité la plus élevée. Un seuil sur la confiance n’ajoute donc pas de vérification indépendante.

Si vous voulez traiter plusieurs annonces en même temps au lieu d’attendre la fin de chaque requête, le SDK inclut AsyncTypeSafeClient.

Ajuster les Seuils avec des Annonces que Vous Avez Vérifiées

Les seuils de 0.8 et 0.5 du code sont des points de départ. Une probabilité ne garantit pas qu’une réponse donnée soit correcte. TypeSafe précise que la calibration, c’est-à-dire l’accord entre les probabilités prédites et les résultats observés, se mesure sur des groupes de prédictions.

Choisissez vos seuils à partir d’annonces issues de vos propres recherches :

  1. Étiquetez à la main 50 à 100 annonces. Notez pour chacune s’il s’agit du même produit, son état et s’il s’agit d’un article seul ou d’un pack. Incluez les mauvaises capacités, les mauvaises couleurs, les étuis, les modèles Shield et les T9 qui se ressemblent.
  2. Passez ces annonces dans ask_jev(). Enregistrez les trois réponses à côté de vos étiquettes.
  3. Comparez les scores à vos étiquettes. Placez SAME_YES au-dessus des non-correspondances que vous ne pouvez pas vous permettre de garder. Utilisez la zone en dessous de ce seuil pour la vérification manuelle.

Une fausse correspondance qui modifie automatiquement des prix peut coûter plus cher qu’une erreur dans un rapport hebdomadaire que quelqu’un relit. Dans le premier cas, relevez SAME_YES. TypeSafe met aussi en garde contre des seuils réglés sur une poignée d’exemples, d’où les 50 annonces de départ plutôt que 5.

Une fois les règles ajustées, utilisez une version fixe du modèle. En novembre 2026, jev-latest pointe vers jev-1.14.0, mais il change à chaque nouvelle version. Vos réponses pourraient donc changer sans aucune modification du code. Utilisez l’identifiant de modèle versionné et enregistrez response.model avec chaque résultat.

Les Limites de Cette Approche

Les Identifiants Exacts d’Abord

Si les deux fiches portent un UPC (le numéro du code-barres) ou une référence fabricant complète, comparez-les dans le code avant d’utiliser un modèle.

Les références Samsung distinguent les variantes : MU-PC1T0T désigne la version 1TB Titan Gray, et MU-PC1T0H la version bleue de 1TB. N’envoyez à Jev que les annonces sans identifiant exploitable. L’endpoint produit de Walmart renvoie un upc, mais les cartes de recherche des trois boutiques n’en ont pas.

Il Vous Faut Toujours des Données d’Annonces Fiables

Jev ne télécharge pas de pages. Collecter des données sur des boutiques qui bloquent les scrapers reste une tâche à part et, à gros volume, c’est généralement l’étape qui casse en premier.

Vos Données Partent vers un Service Externe

Les champs des annonces et votre produit de référence sont envoyés à l’API de TypeSafe. Vérifiez que vos règles de traitement des données l’autorisent avant d’utiliser ce workflow.

FAQ

Puis-je rapprocher des produits entre boutiques sans modèle d’IA ?

Oui. Si les deux annonces partagent un UPC, un EAN ou une référence fabricant, normalisez son format et faites le rapprochement sur cet identifiant. La similarité des titres ne suffit pas, à elle seule, à distinguer de façon fiable capacités, couleurs et accessoires.

Pourquoi pas une seule Choice avec “identique”, “différent” et “accessoire” comme options ?

Parce qu’il vous faut quand même des vérifications séparées pour l’état et la quantité. Le bon produit peut être d’occasion ou vendu par lot de 2. Des questions séparées laissent votre code appliquer vos propres règles à ces faits au lieu de dépendre d’une étiquette combinée.

Puis-je vérifier plusieurs annonces dans une seule requête Jev ?

Oui. La documentation Noul de TypeSafe montre une fiche comparée à plusieurs candidats dans une seule requête, avec un Noul par candidat. La requête doit tenir dans la limite par défaut de Jev 1.14, 64k tokens. Une annonce par requête reste plus simple à ajuster, car chaque jeu de réponses correspond à une seule annonce.

Est-ce que cela fonctionne pour d’autres boutiques qu’Amazon, Walmart et eBay ?

Oui. Jev évalue les champs que vous lui fournissez, pas la boutique elle-même. Collectez les champs d’une autre boutique avec getPageSource et parsed_data=true, ramenez-les à la même structure listing et gardez le reste du workflow.

Commencez par un Seul Produit

Choisissez un produit que vous suivez. Remplissez son objet de référence, y compris les modèles ressemblants que vous connaissez déjà, et lancez compare() sur une recherche. Vérifiez les annonces envoyées en vérification et utilisez ces étiquettes comme premier jeu de réglage.

L’étape de collecte de ce guide utilise les endpoints marketplace de ScrapeUnblocker. La documentation du plugin Amazon liste les paramètres et champs disponibles, avec les pages Walmart et eBay juste à côté. Vous pouvez obtenir une clé d’API sur app.scrapeunblocker.com.

Essayez ScrapeUnblocker gratuitement

Taux de réussite de plus de 95 % · à partir de 0,55 € pour 1 000 appels (TVA éventuelle en sus) · 500 requêtes gratuites à l'inscription.

Essayer gratuitement → Voir les tarifs