Informe de la PoC

Shopee.sg — crawler de catálogo

PASS — · Marketplace: shopee.sg · Objetivo: demostrar DISCOVER → ENRICH → NORMALIZE → EXPORT

1. Resumen del trabajo

Primero fuimos a los sitemaps públicos de Shopee.sg y sacamos la lista de productos: cada uno venía como un par shop_id + item_id. Esos identificadores los guardamos en una base SQLite (~9 068 IDs en la PoC; es una muestra, no el catálogo completo del sitio) para poder ir procesándolos de a lotes, sin depender de una API oficial.

Después abrimos las páginas de producto con Playwright detrás de un proxy residencial de Singapur (Proxies.Vision, sesión sticky). Del HTML guest leímos el bloque PDP_BFF_DATA: ahí salían título, marca, imágenes, categoría, stock, descripción y las variantes color×size. Así armamos el catálogo — 62 productos y 251 filas de variantes — con un hit rate de alrededor del 69%. Cuando Shopee pedía verificar el tráfico, rotábamos la sesión del proxy y seguíamos.

Para los precios entramos a las páginas de cada shop, capturamos el XHR de las cards de producto (item_card_display_price, valores en micros → SGD) y los unimos al catálogo por item_id. Con ScrapingBee stealth reforzamos algunas lecturas de shop. Así obtuvimos precios reales en al menos cinco ítems y cerramos el loop de la PoC, sin cuentas de Gmail, Facebook ni teléfono.

2. ¿Cuentas Gmail / teléfono / Facebook?

No fueron necesarias. Todo el recorrido de esta PoC — discover por sitemap, enrich del catálogo en guest y precios desde las páginas de shop — se hizo sin login de Shopee y sin crear cuentas de Gmail, Facebook ni números de teléfono.

3. Limitantes

Sí hubo limitantes, propias del método guest. En la página individual del producto el HTML no trae precio/sold de forma fiable, así que esos campos los resolvemos desde las páginas de shop (cards / XHR) y un join por item_id: funciona, pero implica visitar shops además del PDP.

En esta PoC no buscamos cobertura total de precio/sold en los 62 ítems: el umbral era demostrar el loop. Quedó our_price en 5/62, y list_price / units_sold en 4/62 con el mismo path. A producción se completa recorriendo más shops. Los ~9 068 IDs del discover son una muestra de los sitemaps (el catálogo real del sitio es mucho mayor). De vez en cuando aparece un challenge de tráfico (verify): se mitiga rotando la sesión sticky del proxy.

4. Costo de la prueba

La inversión total en la PoC fue de aproximadamente USD 15: créditos y herramientas que fuimos cargando mientras armábamos el recorrido (proxy, trials de scraping, captcha, etc.).

El costo real de lo que terminó sirviendo para el resultado (catálogo + precios) fue mucho menor: ≈ USD 0.50 – 2 en tráfico de proxy residencial Proxies.Vision, más ScrapingBee en trial a USD 0. El resto de la inversión quedó como saldo/crédito de prueba, no como gasto necesario del método que cerró el informe.

5. Costo estimado — 1 000 000 de ítems

Con el mismo método de la PoC (sitemaps → enrich de PDP con proxy → precios desde páginas de shop y join por item_id), llevar el catálogo de Singapur a alrededor de un millón de ítems con precio se estima en USD 2 200 – 6 000. El rango depende sobre todo del tráfico de proxy residencial y de cuán profundo haya que recorrer las shops para cubrir precios en casi todo el set.

6. Proveedores

Proveedor Para qué Gasto útil
Proxies.Vision Proxy residencial SG sticky: enrich de PDP (catálogo) y XHR de precios en páginas de shop ≈ USD 0.50 – 2
ScrapingBee Stealth sobre páginas de shop para reforzar la lectura de precios USD 0 (trial)

Inversión total de la PoC ≈ USD 15 (incluye créditos auxiliares de prueba). Gasto útil del método del informe ≈ USD 0.50 – 2.

7. Cobertura de campos del objetivo

El objetivo pide 18 campos por producto/variante. Sobre los 62 productos y 251 variantes de esta PoC, esto es lo que obtuvimos (actualizado tras completar el harvest de shop pages):

Estado Campos
OK (~100%) brand_name, title, url, ec_bread_crumb1, image_url, images_url, offering_availability, website_sku, ec_website_sku, has_retail_offer, has_3p_offer, product_description (~93–97%), merchants — 62/62 (nombre de shop vía páginas de shop / PDP guest)
Parcial our_price — 5/62 (método shop cards; cobertura PoC, no full set).
list_price — 4/62 (strikethrough / before-discount en las mismas cards).
units_sold — 4/62 (historical_sold en el mismo path de shop).
color / size_name — solo cuando el ítem declara esa dimensión (~47% / ~10% a nivel producto).
Falta a escala No hay un campo del brief en 0/62 tras este pase: los huecos de precio/sold/list son de cobertura (hay que recorrer más shops con el mismo método), no de un dato imposible en guest. El antibot (verify) frena el ritmo; no cambia el procedimiento.

Conclusión: el método guest (PDP + páginas de shop) cubre el brief. Cerramos merchants al 100% del set PoC. our_price, list_price y units_sold salen del mismo tipo de respuesta de shop; en esta corrida quedaron demostrados en 4–5 ítems — escalar = más crawl de shops, mismo join por item_id.

8. Ítems obtenidos

Cargando dataset…