feat(shell): auto-commit con 31 cambios
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
---
|
||||
name: scrape_amazon_bestsellers
|
||||
kind: function
|
||||
lang: py
|
||||
domain: datascience
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "def scrape_amazon_bestsellers(marketplace: str = 'amazon.es', categories: list[str] | None = None, list_type: str = 'bestsellers', max_items: int = 50) -> list[dict]"
|
||||
description: "Scrapea los rankings de Amazon (Best Sellers y Movers & Shakers) de un marketplace para captar señales de demanda de productos: rank, ASIN, titulo, precio, rating, reseñas y, en movers, el cambio porcentual."
|
||||
tags: [amazon, scraping, trends, market-intel, datascience]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: [requests, bs4]
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "python/functions/datascience/scrape_amazon_bestsellers.py"
|
||||
params:
|
||||
- name: marketplace
|
||||
desc: "Dominio Amazon objetivo (amazon.es, amazon.com, amazon.co.uk, amazon.de, ...). Determina la URL, el Accept-Language enviado y la moneda fallback."
|
||||
- name: categories
|
||||
desc: "Lista de slugs de categoria a scrapear (ej. 'electronics', 'videogames'). Si es None, scrapea la portada general del ranking elegido. Cada slug genera una pagina/peticion."
|
||||
- name: list_type
|
||||
desc: "Tipo de ranking: 'bestsellers' (URL /gp/bestsellers/<cat>) o 'movers_shakers' (URL /gp/movers-and-shakers/<cat>). Cualquier otro valor lanza ValueError."
|
||||
- name: max_items
|
||||
desc: "Numero maximo de productos recolectados por categoria. Default 50 (una pagina de ranking suele tener ~50 items)."
|
||||
output: "Lista de dicts, uno por producto, con exactamente estas claves: marketplace, list_type, category, rank, asin, title, price, currency, rating, reviews, pct_change, url. None donde no haya dato. price/rating/pct_change son float; rank/reviews son int. pct_change solo se rellena en movers_shakers. Casa 1:1 con la tabla Postgres amazon_bestsellers (el ingest añade id/snapshot_date/scraped_at)."
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```python
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join("python", "functions"))
|
||||
from datascience.scrape_amazon_bestsellers import scrape_amazon_bestsellers
|
||||
|
||||
# Best Sellers de electronica y videojuegos en Amazon.es
|
||||
rows = scrape_amazon_bestsellers(
|
||||
marketplace="amazon.es",
|
||||
categories=["electronics", "videogames"],
|
||||
list_type="bestsellers",
|
||||
max_items=50,
|
||||
)
|
||||
print(len(rows), "items")
|
||||
print(rows[0])
|
||||
# {'marketplace': 'amazon.es', 'list_type': 'bestsellers', 'category': 'electronics',
|
||||
# 'rank': 1, 'asin': 'B0...', 'title': '...', 'price': 29.99, 'currency': 'EUR',
|
||||
# 'rating': 4.5, 'reviews': 1234, 'pct_change': None, 'url': 'https://www.amazon.es/dp/B0...'}
|
||||
|
||||
# Movers & Shakers (productos que mas suben) — incluye pct_change
|
||||
movers = scrape_amazon_bestsellers(
|
||||
marketplace="amazon.com",
|
||||
list_type="movers_shakers",
|
||||
max_items=30,
|
||||
)
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Usala cuando necesites captar señales de demanda de mercado desde Amazon: que se esta vendiendo mas (Best Sellers) o que esta subiendo de golpe en ventas (Movers & Shakers), por marketplace y categoria. Util como fuente de un pipeline de market intelligence / trend detection que luego ingesta a la tabla `amazon_bestsellers` y cruza snapshots diarios para detectar productos al alza. Llamala antes de cualquier analisis de tendencias de catalogo; el dict devuelto esta listo para insertar tras añadir `snapshot_date`/`scraped_at`.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Anti-bot fuerte**: Amazon detecta scraping HTTP puro y puede devolver captcha, `503` o `429`. La funcion detecta el bloqueo (status 429/503 o markers de captcha en el HTML) y, tras agotar reintentos, lanza `RuntimeError` con el status. **Si HTTP puro falla repetidamente, la alternativa es el navegador del ecosistema (browser MCP / CDP)** sobre una pestaña real de Chrome, que pasa el anti-bot mejor que `requests`.
|
||||
- **HTML fragil**: Amazon cambia las plantillas del DOM con frecuencia y sirve varias a la vez segun A/B test. Los selectores estan escritos defensivamente (varios fallbacks por campo) pero **pueden necesitar mantenimiento** cuando Amazon rota plantillas. Si un campo no aparece en ninguna plantilla conocida, se devuelve `None` en vez de petar.
|
||||
- **Campos opcionales = None**: no todos los items traen precio/rating/reviews/pct_change. `pct_change` solo se rellena en `list_type="movers_shakers"`; en bestsellers siempre es `None`.
|
||||
- **rank fallback posicional**: si Amazon no renderiza el badge de rank, se usa la posición (1-indexada) del item en la pagina como rank.
|
||||
- **Una peticion por categoria**: cada slug en `categories` dispara una peticion HTTP independiente (con 2 reintentos + backoff). Listas largas de categorias multiplican el riesgo de throttling — espacia las llamadas si scrapeas muchas.
|
||||
- **Moneda best-effort**: `currency` se infiere del simbolo en el precio (€, $, £, R$) y, si no hay simbolo reconocible, del TLD del marketplace. Puede ser `None` si no se pudo determinar.
|
||||
Reference in New Issue
Block a user