Encontrar precios ocultos mediante ingeniería inversa de las llamadas a la API de fondo
Encuentra precios que nunca aparecen en el HTML observando DevTools para las llamadas XHR, REST y GraphQL detrás de la página, y luego reproduciendo esas solicitudes directamente.
Segunda parte de la serie “Cómo funciona realmente el scraping”
En el artículo anterior nos topamos con un problema: a veces el precio que necesitamos simplemente no está presente en ningún lugar del HTML que obtiene requests. No está incrustado en JSON-LD, ni escondido en una etiqueta meta; simplemente no se encuentra por ningún lado. Eso no significa que estemos atascados: generalmente solo significa que la página carga esa información después de la carga inicial, a través de una llamada en segundo plano separada. El objetivo aquí es localizar esa llamada y realizarla nosotros mismos.
Paso 1: Abrir la pestaña Red
Vamos a trabajar con un ejemplo concreto: una página de producto en el sitio de Target, target.com/p/dyson-ball-animal-3-upright-vacuum/-/A-85269291 (esto es solo para demostración; el mismo enfoque funciona en prácticamente cualquier página de producto).
- Cargar cualquier página de producto.
F12). Paso 2: Localice la solicitud que realmente necesita
Vaya revisando la lista una entrada a la vez, haciendo clic en cada una y consultando su panel Respuesta o Vista previa en el lado derecho. Está buscando un contenido JSON que contenga el precio, la cantidad de reseñas o cualquier otro valor que necesite.
Existe una ruta más rápida: utilice el cuadro de búsqueda con lupa dentro de la pestaña Network e introduzca un valor que sea visible en la propia página. En el ejemplo de Target, al escribir “449.99” se accede directamente a una llamada POST denominada deferred_enrichment/modules. Su cuerpo de respuesta es un objeto JSON bastante extenso, y dentro de él encontrará “formatted_current_price”: “$449.99”.
Paso 3: Reproduzca la llamada usted mismo
Seleccione esa solicitud y obtenga su URL completa. En este caso se trata de una solicitud POST, pero todo lo necesario ya está presente en la cadena de consulta:
https://www.target.com/cdui_orchestrations/v1/pages/pdp/deferred_enrichment/modules
?tcin=85269291
&key=9f36aeafbe60771e321a7cc95a78140772ab3e96
&channel=WEB
&device_type=DESKTOP
Así es como se ve al reproducirlo 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
Ese es todo el truco. Sin bibliotecas de análisis, sin selectores CSS que supervisar: simplemente envía la misma consulta que el propio JavaScript de la página envía en segundo plano.
Consejo: en DevTools, haga clic con el botón derecho en la solicitud y elija Copy → Copy as cURL. De esta manera obtendrá los encabezados y cookies exactos que el navegador envió, los cuales puede copiar a un cliente como Postman o convertirlos a Python para determinar con precisión qué partes son realmente necesarias.
Paso 4: Cuando la API es GraphQL
Algunos sitios enrutan todo a través de GraphQL en lugar de una configuración REST tradicional. Puede reconocer este patrón porque cada llamada llega al mismo endpoint (con frecuencia /graphql), y la pregunta real que se hace se encuentra en el cuerpo de la solicitud en lugar de en la URL:
{
"operationName": "GetPrice",
"variables": { "productId": "12345" },
"query": "query GetPrice($productId: ID!) { product(id: $productId) { price } }"
}
Varios sitios van aún más allá con una consulta persistente, donde en lugar de transmitir el texto completo de la consulta, el cliente envía solo un hash breve que la representa:
/graphql/GetPrice/a1b2c3d4e5f6...?variables={"productId":"12345"}
Ese hash no es algo que puedas derivar por tu cuenta; debes obtenerlo directamente desde DevTools. Y como está vinculado a la compilación del frontend del sitio, una actualización por su parte puede cambiar el hash y dañar silenciosamente tu script. Ese es un costo real y constante de depender de esta técnica.
Paso 5: Verificar si esa clave API es realmente privada
Mira nuevamente la URL de destino del Paso 3: fíjate en key=9f36aeafbe60771e321a7cc95a78140772ab3e96 que aparece abiertamente en la cadena de consulta. ¿Es algo al que no deberías tener acceso?
Por lo general, no. La forma más rápida de verificarlo es abrir Ver código fuente de la página (Ctrl+U) y luego buscar apiKey con Ctrl+F. Encontrarás esa misma clave en texto plano, dentro de un bloque de configuración que Target envía a cada visitante.
Si un valor ya se encuentra en el propio marcado de la página, sin que nada haya sido evadido ni esté involucrada ninguna autenticación, en realidad nunca fue confidencial desde un principio. Se trata simplemente de una clave pública destinada a ejecutarse en el navegador. (Ocasionalmente se encuentra en un archivo .js separado; si al ver el código fuente no aparece nada, pruebe con el panel Sources de DevTools y busque con Ctrl+Shift+F.)
Una buena práctica: antes de tomarse la molestia de realizar ingeniería inversa de un endpoint, verifique si la empresa ya ofrece una API pública o para socios documentada. Estas suelen ser mucho más estables que aquellas que se descubren explorando DevTools.
Paso 6: Cuando los datos no provienen en absoluto del minorista
A veces, la solicitud que se localiza ni siquiera va al dominio propio del minorista; en su lugar, apunta a un servicio de terceros como bazaarvoice.com o judge.me. Eso indica que el minorista no utiliza su propia infraestructura de reseñas, sino que licencia el sistema de un proveedor e incluye simplemente su widget en la página.
Estas API de widgets gestionadas por proveedores suelen tener menos medidas de seguridad que el sitio principal del minorista, ya que están diseñadas para integrarse en miles de tiendas online no relacionadas y no específicamente para detectar ni bloquear robots de extracción de datos.
Lo que este artículo omite deliberadamente
Si ha seguido todos los pasos anteriores y la solicitud que necesita sigue devolviendo un 403, un cuerpo vacío o algo similar a un punto de control de seguridad en lugar de datos reales, eso no es un error en su código. Significa que el sitio ha detectado activamente que no se trata de una sesión de navegador normal. Ese desafío es lo suficientemente importante como para merecer un análisis aparte, y ahí es exactamente donde continúa el siguiente artículo.
Glosario
Pestaña Network — el panel de DevTools que registra cada solicitud que realiza una página, junto con lo que se envió y lo que se recibió.
XHR / Fetch — los dos mecanismos que utiliza JavaScript para realizar solicitudes en segundo plano sin recargar toda la página; la pestaña Network puede filtrarse para mostrar solo estas.
REST API — un patrón de API común en el que cada recurso tiene su propia URL dedicada, como /products/123/price.
GraphQL — un estilo de API basado en un único endpoint, donde el cuerpo de la solicitud especifica con exactitud qué datos se están solicitando.
Persisted query — una abreviatura de GraphQL en la que el texto completo de la consulta se reemplaza por un hash compacto que el servidor ya reconoce.
API key — un valor asociado a una solicitud para identificarla; algunas son realmente privadas, pero muchas son claves públicas orientadas a clientes que pueden verse en el navegador de cualquier persona.
Copiar como cURL — una opción de DevTools que convierte una solicitud capturada en una llamada desde la línea de comandos ejecutable, útil para inspeccionar sus encabezados y cookies exactos.
Widget de terceros — una función, como una sección de reseñas, que un sitio no desarrolla internamente sino que integra a partir del producto de otra empresa.
Lecturas relacionadas
- Elegir un marco de trabajo para agentes de IA en Python en 2026: Un comparativo práctico — Compara cinco marcos de trabajo para agentes de IA en Python según su manejo de fallos y complejidad, ayudando a los lectores a elegir la herramienta adecuada para su flujo de trabajo.
- El herramientario oculto de JavaScript: Símbolos, WeakMaps, Proxies y generadores — Aprenda cómo funcionan los símbolos, WeakMap/WeakSet, Proxy/Reflect, FinalizationRegistry y los generadores en el fondo para prevenir fugas de memoria y permitir la metaprogramación a nivel de framework.