Monitorear precios de competidores

Configura la monitorización automatizada de precios en sitios web de la competencia mediante la API de FourA.

Lo que vas a construir

Un script de Python que:

  1. Obtiene páginas de productos a partir de una lista de URL de competidores
  2. Extrae datos de precios del HTML
  3. Registra los resultados en un archivo CSV
  4. Se ejecuta de forma programada

Requisitos previos

  • Una clave de API de FourA (obtén una aquí)
  • Python 3.8+
  • Paquetes requests y beautifulsoup4
pip install requests beautifulsoup4

Paso 1: Define tus objetivos

Crea una lista de URL de productos para monitorear:

targets = [
    {"name": "Competitor A - Widget", "url": "https://competitor-a.com/widget", "selector": ".price"},
    {"name": "Competitor B - Widget", "url": "https://competitor-b.com/products/widget", "selector": "[data-price]"},
    {"name": "Competitor C - Widget", "url": "https://competitor-c.com/item/123", "selector": ".product-price span"},
]

Paso 2: Obtén páginas mediante FourA

import requests
import time

SINGLE_URL = "https://eu.api.foura.ai/api/single/"
BROWSER_URL = "https://eu.api.foura.ai/api/browser/"
API_KEY = "YOUR_API_KEY"

HEADERS = {
    "X-API-Key": API_KEY,
    "Content-Type": "application/json"
}

# A wait doesn't clear these: they reset with the period (credits, traffic)
# or at midnight UTC (the daily Browser allowance).
STOP_LIMITS = {"plan_limit_credits", "plan_limit_bandwidth", "plan_limit_browser_daily"}

def fetch_page(url, use_browser=False, attempts=3):
    if use_browser:
        endpoint, field = BROWSER_URL, "body"
        payload = {"url": url, "timeout_ms": 15000}
    else:
        endpoint, field = SINGLE_URL, "data"
        payload = {"method": "GET", "url": url, "unblocker": True}
    for _ in range(attempts):
        resp = requests.post(endpoint, headers=HEADERS, json=payload)
        if resp.status_code != 429:
            return resp.json().get(field, "")
        limit = resp.headers.get("X-FourA-Limit")
        if limit in STOP_LIMITS:
            raise RuntimeError(f"Plan limit reached: {limit}")
        time.sleep(int(resp.headers.get("Retry-After", "5")))
    raise RuntimeError(f"Still rate limited after {attempts} attempts: {url}")

Un 429 con plan_limit_credits, plan_limit_bandwidth o plan_limit_browser_daily en X-FourA-Limit no se solucionará esperando unos segundos, por lo que la función se detiene en lugar de reintentar. Consulta Rate Limits para conocer cada límite y cuándo se reinicia.

Paso 3: Extraer precios

from bs4 import BeautifulSoup
import re

def extract_price(html, selector):
    soup = BeautifulSoup(html, "html.parser")
    element = soup.select_one(selector)
    if not element:
        return None
    # Extract numeric price from text like "$49.99" or "49,99 EUR"
    text = element.get_text(strip=True)
    match = re.search(r'[\d,.]+', text)
    return float(match.group().replace(',', '.')) if match else None

Paso 4: Ejecutar y registrar resultados

import csv
from datetime import datetime

def monitor_prices():
    timestamp = datetime.now().isoformat()
    results = []

    for target in targets:
        html = fetch_page(target["url"])
        price = extract_price(html, target["selector"])
        results.append({
            "timestamp": timestamp,
            "name": target["name"],
            "url": target["url"],
            "price": price
        })
        print(f"{target['name']}: {price}")
        time.sleep(1)  # Be polite

    # Append to CSV
    with open("prices.csv", "a", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=["timestamp", "name", "url", "price"])
        if f.tell() == 0:
            writer.writeheader()
        writer.writerows(results)

if __name__ == "__main__":
    monitor_prices()

Paso 5: Prográmalo

Ejecuta el script cada hora con cron:

crontab -e
# Add this line:
0 * * * * cd /path/to/project && python3 monitor.py >> monitor.log 2>&1

Consejos

  • Comienza con el endpoint simple, cambia a browser si las páginas usan renderizado con JavaScript
  • Agrega manejo de errores: los sitios cambian de diseño. Registra los fallos por separado.
  • Mantén los selectores actualizados: cuando un competidor rediseñe su sitio, actualiza el selector CSS
  • Respeta los sitios: espacia las requests, evita horas pico y sigue el robots.txt

Próximos pasos

Actualizado: 23 de septiembre de 2026