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.

← Todos los artículos

Cómo Identificar el Mismo Producto en Anuncios de Amazon, Walmart y eBay con Jev

Buscas en Amazon, Walmart y eBay un Samsung T7 Portable SSD de 1TB en Titan Gray. Obtienes un centenar de anuncios, pero todavía no puedes comparar precios. Antes tienes que separar ese disco exacto de la versión de 2TB, de la versión azul, de las fundas de transporte y de las unidades usadas.

Ni siquiera un título idéntico basta. Un anuncio puede nombrar el producto correcto mientras los datos del vendedor revelan que se trata de una oferta usada o de caja abierta.

Esta guía construye el paso de emparejamiento en Python. Recoges datos estructurados de los anuncios, le haces a Jev tres preguntas sobre cada resultado y luego usas código para conservarlo, mandarlo a revisión o descartarlo. Los ejemplos vienen de búsquedas reales hechas el 8 de noviembre de 2026.

Por Qué No Bastan los Títulos Parecidos

Lo primero que se suele probar es la coincidencia difusa (fuzzy matching): medir cuánto se parecen dos textos. Puedes usar RapidFuzz para comparar el título de cada anuncio con tu título de referencia y quedarte con todo lo que supere una puntuación.

El problema es que una puntuación alta de similitud de texto no significa necesariamente que sea el mismo producto.

Estos son los resultados de RapidFuzz 3.13 para la referencia Samsung T7 Portable SSD 1TB Titan Gray (MU-PC1T0T/AM). La comparación usa processor=utils.default_process para normalizar el texto antes de puntuar. token_set_ratio y WRatio son dos métodos de puntuación:

Título del anuncio (acortado)Tiendatoken_set_ratioWRatioQué es en realidad
Samsung T7 Portable SSD 1TB Titan Gray, Up-to 1,050MB/s … (MU-PC1T0T/AM)Walmart100.085.5El producto
Samsung MU-PC2T0T T7 2TB Portable SSD Titan Gray USB 3.2eBay87.983.5Capacidad equivocada
Samsung T7 1TB (MU-PC1T0T/AM) USB 3.2 Gen 2 External SSD FACTORY SEAL - GRAYeBay82.878.6El producto
SAMSUNG T7 Portable SSD, 1TB … MU-PC1T0H/AM, BlueAmazon78.685.5Color equivocado
Samsung T7 Shield 1TB … Black, with HD-2 Drive CaseWalmart69.285.5Otro modelo, con funda incluida
Paiyule Carrying Case for Samsung T9/T7/T7 Shield Portable SSD 4TB 2TB 1TBAmazon69.265.8Un accesorio

Con token_set_ratio, el disco equivocado de 2TB puntúa más alto que una coincidencia real. Cualquier umbral que conserve ese anuncio auténtico de eBay también conserva la capacidad equivocada. Con WRatio, el disco azul y el pack del T7 Shield empatan con la coincidencia exacta de Walmart.

Las palabras que deciden si debes quedarte con un anuncio, como “2TB”, “Blue” o “Case”, son solo una pequeña parte del título.

La información que falta es otro problema. Un resultado de Amazon tenía el título Samsung T7 Portable SSD 1TB Titan Gray, USB 3.2 Gen 2, Up to 1,050MB/s. Puntuó 85.4 y, en el momento de escribir esto, costaba 230.01 $ frente a un precio de lista de 274.99 $. Pero su página de producto decía “Sold by Amazon Resale”, la tienda de Amazon para devoluciones usadas y de caja abierta. Una comparación de títulos no puede detectar información que no está en el título.

Podrías pedirle a un modelo de chat que juzgue cada anuncio y devuelva JSON, un formato de datos estructurado que tu código puede leer. Pero aun así tendrías que validar la respuesta generada y, a veces, repetir la petición. Además, un simple “sí” no te da ningún umbral numérico para decidir qué resultados dudosos necesitan revisión.

Qué Aporta Jev al Flujo

Jev devuelve respuestas tipadas: resultados con formas predefinidas en lugar de texto generado. TypeSafe lo describe como su primer modelo “System One”. A noviembre de 2026, acepta la información que hay que evaluar, llamada state, junto con preguntas de los tipos Choice, Score, Noul o Box.

Aquí necesitas dos de esos tipos:

  • Noul: una pregunta de sí o no que devuelve la probabilidad de “sí”. La usas para preguntar si un anuncio es el mismo producto.
  • Choice: una pregunta con opciones que tú defines. Devuelve la opción elegida, una probabilidad para cada opción y un valor de confianza. La usas para clasificar el estado del artículo.

Tu código en Python lee esos resultados y aplica tus reglas de emparejamiento. La página de modelos de TypeSafe indica un precio de 0.042 $ por millón de tokens de entrada, las unidades con las que se mide la entrada del modelo, y los tokens de salida son gratuitos.

Jev no escribe texto ni extrae un título y un precio de una página HTML. Tienes que reunir los campos del anuncio antes de enviarlos.

Recoge los Anuncios en JSON

Cada tienda tiene su propia estructura de página y sus propios sistemas para bloquear peticiones automatizadas. Este ejemplo usa los endpoints de marketplace de ScrapeUnblocker, rutas de API dedicadas que devuelven los resultados de búsqueda en JSON, en lugar de escribir un parser distinto para cada tienda.

Cada llamada usa el método HTTP POST, pone los parámetros de búsqueda en la query string de la URL y envía tu clave de acceso en la cabecera x-scrapeunblocker-key.

El siguiente código recoge los campos de los anuncios de las tres tiendas. Los nombres de los campos salen de respuestas reales.

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

Tres decisiones en la recogida afectan al emparejamiento:

  • Pide también el detalle del producto en Amazon. Las tarjetas de búsqueda no incluyen la línea del vendedor que delata la oferta de Amazon Resale. /marketplace/amazon-product devuelve seller y las viñetas de features. Cuesta una petición extra por ASIN, el identificador de producto de Amazon, así que max_details limita cuántas peticiones de detalle haces.
  • Mantén los precios de eBay en USD. eBay puede convertir los precios a la moneda local del visitante. La petición fija proxy_country=US y la comparación posterior descarta los precios que no estén en USD. ebay_listings() además no devuelve nada cuando la respuesta dice exactMatches: false, que marca las sugerencias aproximadas de eBay cuando no encuentra una coincidencia exacta.
  • Deja fuera los campos que no ayudan. Una tarjeta de Walmart nombraba la versión de 1TB en el título, pero describía la de 500GB en su fragmento de descripción. Este ejemplo omite la descripción para no enviar esos datos contradictorios.

Puedes añadir Google Shopping con /goods/google-shopping. Para una tienda sin endpoint dedicado, getPageSource con parsed_data=true devuelve los campos del producto en JSON. Consulta la guía de datos parseados para ese enfoque, o esta respuesta sobre scraping de precios en e-commerce para recoger precios y niveles de stock.

Haz Tres Preguntas Sobre Cada Anuncio

Instala el SDK de TypeSafe, su librería de Python, con pip install typesafe-sdk y define TYPESAFE_API_KEY con tu clave de API.

El siguiente código envía una petición por anuncio. Pone tu producto de referencia y el anuncio candidato en el state y pregunta si el producto coincide, en qué estado está y si es un artículo suelto y no 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 petición tiene esta estructura por varias razones:

  • Pon nombre a la información que envías. El state tiene partes separadas, listing y reference. TypeSafe recomienda este objeto estructurado antes que un texto plano, y las preguntas se refieren a esos nombres.
  • Incluye lo que sabes del producto. Jev no está entrenado con tu catálogo. El campo different_models le habla de los modelos que se parecen, y la pista de Amazon Resale en la opción used le ayuda a interpretar ese dato del vendedor.
  • Un hecho por pregunta. “El disco correcto, nuevo, unidad suelta” contiene tres comprobaciones. TypeSafe aconseja una sola pregunta de sí o no por Noul y combinar los resultados en el código. Las preguntas se evalúan en paralelo dentro de la petición.
  • Incluye el precio. Un anuncio de 9.99 $ presentado como SSD es una buena pista de que puede ser un accesorio y no el disco.

Decide Qué Conservar, Revisar o Descartar

Las respuestas del modelo son datos para tu decisión, no la decisión final. El siguiente código aplica umbrales de probabilidad y asigna cada anuncio a conservar, revisar o descartar.

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() mira primero same_product. El orden importa porque la Choice de estado siempre elige una de sus cuatro opciones, incluso cuando el anuncio es de otro disco. La respuesta sobre el estado solo tiene sentido después de confirmar que el producto coincide. TypeSafe llama a esto el patrón companion Noul.

Para la respuesta de la Choice, el código comprueba probabilities[choice], la probabilidad asignada a la opción elegida, y no confidence. La documentación de TypeSafe sobre enrutar por probabilidad explica que, en una Choice con opciones fijas, la confianza se calcula a partir de la probabilidad más alta. Por eso un umbral sobre la confianza no añade una comprobación independiente.

Si quieres procesar varios anuncios a la vez en lugar de esperar a que termine cada petición, el SDK incluye AsyncTypeSafeClient.

Ajusta los Umbrales con Anuncios que Ya Has Revisado

Los umbrales de 0.8 y 0.5 del código son puntos de partida. Una probabilidad no garantiza que una respuesta concreta sea correcta. TypeSafe señala que la calibración, es decir, cuánto se ajustan las probabilidades previstas a los resultados observados, se mide sobre grupos de predicciones.

Elige tus umbrales con anuncios de tus propias búsquedas:

  1. Etiqueta a mano entre 50 y 100 anuncios. Anota si cada uno es el mismo producto, su estado y si es una unidad suelta o un pack. Incluye capacidades y colores equivocados, fundas, modelos Shield y los T9 que se parecen.
  2. Pasa ask_jev() por esos anuncios. Guarda las tres respuestas junto a tus etiquetas.
  3. Compara las puntuaciones con tus etiquetas. Pon SAME_YES por encima de los no coincidentes que no puedes permitirte conservar. Usa la franja por debajo de ese umbral para la revisión manual.

Una coincidencia falsa que cambia precios automáticamente puede salir más cara que una en un informe semanal que alguien revisa. En el primer caso, sube SAME_YES. TypeSafe también advierte contra ajustar los umbrales con solo un puñado de ejemplos, y por eso aquí se empieza con 50 anuncios y no con 5.

Cuando hayas ajustado las reglas, usa una versión fija del modelo. A noviembre de 2026, jev-latest apunta a jev-1.14.0, pero cambia cuando sale una nueva versión. Tus respuestas podrían cambiar sin tocar el código. Usa el ID de modelo versionado y guarda response.model con cada resultado.

Dónde se Queda Corto Este Enfoque

Los Identificadores Exactos Van Primero

Si los dos registros llevan un UPC (el número del código de barras) o un número de pieza completo del fabricante, compáralos en el código antes de usar un modelo.

Los números de pieza de Samsung distinguen las variantes: MU-PC1T0T identifica la versión de 1TB en Titan Gray y MU-PC1T0H la versión azul de 1TB. Envía a Jev solo los anuncios sin un identificador utilizable. El endpoint de producto de Walmart devuelve un upc, pero las tarjetas de búsqueda de las tres tiendas no.

Sigues Necesitando Datos de Anuncios Fiables

Jev no descarga páginas. Recoger datos de tiendas que bloquean scrapers sigue siendo una tarea aparte y, a gran volumen, suele ser el paso que falla primero.

Tus Datos Van a un Servicio Externo

Los campos de los anuncios y tu producto de referencia se envían a la API de TypeSafe. Comprueba que tus normas de tratamiento de datos lo permiten antes de usar este flujo.

Preguntas Frecuentes

¿Puedo emparejar productos entre tiendas sin un modelo de IA?

Sí. Si los dos anuncios comparten un UPC, un EAN o un número de pieza del fabricante, normaliza su formato y empareja por ese identificador. La similitud de títulos por sí sola no separa de forma fiable capacidades, colores y accesorios.

¿Por qué no una sola Choice con “igual”, “distinto” y “accesorio” como opciones?

Porque sigues necesitando comprobaciones separadas para el estado y la cantidad. El producto correcto puede estar usado o venderse en un pack de 2. Las preguntas separadas permiten que tu código aplique tus propias reglas a esos hechos en lugar de depender de una etiqueta combinada.

¿Puedo revisar muchos anuncios en una sola petición a Jev?

Sí. La documentación de Noul de TypeSafe muestra un registro comparado con varios candidatos en una sola petición, con un Noul por candidato. La petición tiene que caber en el límite por defecto de Jev 1.14, 64k tokens. Un anuncio por petición es más fácil de ajustar, porque cada conjunto de respuestas pertenece a un solo anuncio.

¿Funciona con tiendas distintas de Amazon, Walmart y eBay?

Sí. Jev evalúa los campos que le das, no la tienda. Recoge los campos de otra tienda con getPageSource y parsed_data=true, pásalos a la misma estructura de listing y mantén el resto del flujo.

Empieza con un Solo Producto

Elige un producto que sigas. Rellena su objeto de referencia, incluidos los modelos parecidos que ya conoces, y ejecuta compare() sobre una búsqueda. Revisa los anuncios que acaben en revisión y usa esas etiquetas como tu primer conjunto de ajuste.

El paso de recogida de esta guía usa los endpoints de marketplace de ScrapeUnblocker. La documentación del plugin de Amazon lista los parámetros y campos disponibles, con la de Walmart y eBay al lado. Puedes conseguir una clave de API en app.scrapeunblocker.com.

Prueba ScrapeUnblocker gratis

Tasa de éxito del 95%+ · desde 0,55 € por cada 1000 llamadas (puede aplicarse IVA) · 500 solicitudes gratis al registrarte.

Pruébalo gratis → Ver precios