Amazon cambia con frecuencia el diseño de los resultados de búsqueda, la ubicación de los anuncios y las estructuras de las tarjetas de productos. Los raspadores se rompen cuando esto sucede. Este tutorial monitorea la estructura SERP de Amazon a través de la API de Scavio, detectando cuándo cambian los formatos de resultados, aparecen nuevos elementos o cambian las posiciones de los productos. Cada cheque cuesta $0,005.
Requisitos previos
- Python 3.8+
- solicita biblioteca
- Una clave API de Scavio de scavio.dev
- Categorías de productos de Amazon para monitorear
Guia paso a paso
Paso 1: Capture instantáneas de la estructura SERP de Amazon
Registre la estructura de los resultados de búsqueda de Amazon, incluidos los tipos y posiciones de los resultados.
import os, requests, json, hashlib
from datetime import datetime
API_KEY = os.environ['SCAVIO_API_KEY']
SH = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
def snapshot_amazon_serp(query):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': query, 'platform': 'amazon', 'country_code': 'us'}, timeout=10).json()
organic = data.get('organic_results', [])
structure = {
'query': query,
'timestamp': datetime.now().isoformat(),
'total_results': len(organic),
'result_types': [],
'has_sponsored': any('sponsored' in json.dumps(r).lower() for r in organic),
'has_ratings': sum(1 for r in organic if r.get('rating')),
'has_prices': sum(1 for r in organic if r.get('price') or r.get('extracted_price')),
'top_domains': list(set(r.get('displayed_link', '').split('/')[0] for r in organic[:5])),
}
for r in organic:
rtype = 'sponsored' if 'sponsored' in json.dumps(r).lower() else 'organic'
structure['result_types'].append(rtype)
content_hash = hashlib.md5(json.dumps(structure['result_types']).encode()).hexdigest()
structure['layout_hash'] = content_hash
return structure
QUERIES = ['wireless earbuds', 'protein powder', 'usb c hub']
for q in QUERIES:
snap = snapshot_amazon_serp(q)
sponsored = snap['result_types'].count('sponsored')
organic = snap['result_types'].count('organic')
print(f' {q:30} | Results: {snap["total_results"]} | Organic: {organic} | Sponsored: {sponsored} | Hash: {snap["layout_hash"][:8]}')
print(f'\nCost: ${len(QUERIES) * 0.005:.3f}')Paso 2: Compara instantáneas para detectar cambios de diseño
Compare instantáneas diarias para encontrar cambios estructurales en los resultados de Amazon.
HISTORY_FILE = 'amazon_layout_history.json'
def save_and_compare(snapshots):
try:
with open(HISTORY_FILE) as f:
history = json.load(f)
except FileNotFoundError:
history = []
today = {'date': datetime.now().strftime('%Y-%m-%d'), 'snapshots': snapshots}
changes = []
if history:
prev_snaps = {s['query']: s for s in history[-1]['snapshots']}
for snap in snapshots:
prev = prev_snaps.get(snap['query'])
if not prev:
continue
if snap['layout_hash'] != prev['layout_hash']:
changes.append({'query': snap['query'], 'type': 'layout_change',
'detail': f'Layout hash changed: {prev["layout_hash"][:8]} -> {snap["layout_hash"][:8]}'})
if snap['total_results'] != prev['total_results']:
changes.append({'query': snap['query'], 'type': 'result_count',
'detail': f'Results: {prev["total_results"]} -> {snap["total_results"]}'})
prev_sponsored = prev['result_types'].count('sponsored')
curr_sponsored = snap['result_types'].count('sponsored')
if prev_sponsored != curr_sponsored:
changes.append({'query': snap['query'], 'type': 'ad_change',
'detail': f'Sponsored: {prev_sponsored} -> {curr_sponsored}'})
history.append(today)
with open(HISTORY_FILE, 'w') as f:
json.dump(history, f, indent=2)
return changes
snapshots = [snapshot_amazon_serp(q) for q in QUERIES]
changes = save_and_compare(snapshots)
print(f'\nLayout changes detected: {len(changes)}')
for c in changes:
print(f' [{c["type"]:15}] {c["query"]:25} | {c["detail"]}')Paso 3: Generar informe de cambio de diseño
Compile los cambios en un informe procesable para los equipos de comercio electrónico.
def layout_change_report(changes, snapshots):
print(f'\n{"=" * 60}')
print(f' Amazon Layout Change Report - {datetime.now().strftime("%Y-%m-%d")}')
print(f'{"=" * 60}')
print(f'\n Queries monitored: {len(snapshots)}')
print(f' Changes detected: {len(changes)}')
# Current structure summary
print(f'\n Current Layout Summary:')
for snap in snapshots:
sponsored = snap['result_types'].count('sponsored')
organic = snap['result_types'].count('organic')
print(f' {snap["query"]:25} | Organic: {organic} | Sponsored: {sponsored} | Prices: {snap["has_prices"]} | Ratings: {snap["has_ratings"]}')
if changes:
by_type = {}
for c in changes:
by_type.setdefault(c['type'], []).append(c)
for ctype, items in by_type.items():
print(f'\n {ctype.replace("_", " ").title()} ({len(items)}):')
for item in items:
print(f' {item["query"]}: {item["detail"]}')
else:
print(f'\n No layout changes since last scan.')
print(f'\n Daily cost: ${len(snapshots) * 0.005:.3f}')
print(f' No scrapers needed. No proxy rotation. No HTML parsing.')
layout_change_report(changes, snapshots)Ejemplo en Python
import os, requests, json, hashlib
SH = {'x-api-key': os.environ['SCAVIO_API_KEY'], 'Content-Type': 'application/json'}
def amazon_layout(query):
data = requests.post('https://api.scavio.dev/api/v1/search',
headers=SH, json={'query': query, 'platform': 'amazon', 'country_code': 'us'}, timeout=10).json()
results = data.get('organic_results', [])
h = hashlib.md5(json.dumps([r.get('position') for r in results]).encode()).hexdigest()[:8]
print(f'{query[:30]:30} | {len(results)} results | hash: {h}')
amazon_layout('wireless earbuds')Ejemplo en JavaScript
const SH = { 'x-api-key': process.env.SCAVIO_API_KEY, 'Content-Type': 'application/json' };
const data = await fetch('https://api.scavio.dev/api/v1/search', {
method: 'POST', headers: SH,
body: JSON.stringify({ query: 'wireless earbuds', platform: 'amazon', country_code: 'us' })
}).then(r => r.json());
console.log(`Results: ${(data.organic_results || []).length}`);Salida esperada
wireless earbuds | Results: 10 | Organic: 7 | Sponsored: 3 | Hash: 4f2a8b1c
protein powder | Results: 10 | Organic: 8 | Sponsored: 2 | Hash: 7d3e9f5a
usb c hub | Results: 10 | Organic: 8 | Sponsored: 2 | Hash: 1b6c4d8e
Cost: $0.015
Layout changes detected: 1
[ad_change ] wireless earbuds | Sponsored: 2 -> 3
============================================================
Amazon Layout Change Report - 2026-05-21
============================================================
Queries monitored: 3
Changes detected: 1
No scrapers needed. No proxy rotation. No HTML parsing.