Inicio / Artículos / Agentes de automatización de navegadores sin restricciones con Node.js

Agentes de automatización de navegadores sin restricciones con Node.js

Construya un agente para navegadores con límites claros de las herramientas, medidas de seguridad y registro funcional.

4302 palabras

Esta guía reconstruye un proceso funcional para: Cómo crear un agente de automatización de navegadores sin restricciones utilizando Node.js, Playwright, Bright Data y Gemini. Se enfoca en contratos, verificaciones y código que se puede insertar en un repositorio sin tener que adivinar la intención. Para obtener una visión general, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Considere esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas.

Introducción

Para la introducción, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Registre los tiempos y costos junto con los resultados funcionales. La visibilidad temprana evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Delimite estrictamente los esquemas de las herramientas; los argumentos de texto libre excesivos facilitan inyecciones y encarecen las auditorías.

await page.goto(url)
await page.click(selector)
await page.type(selector, text)

Qué estamos construyendo

Para lo que estamos construyendo, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan realizar auditorías sin tener que leer todo el sistema. Delimite estrictamente los esquemas de las herramientas. Los argumentos de texto libre amplios invitan a inyecciones y hacen que las auditorías sean costosas.

Requisito previo

Como requisito previo, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea desde un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las intentonas repetidas, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Delimite estrictamente los esquemas de las herramientas. Los argumentos de texto libre amplios invitan a inyecciones y hacen que las auditorías sean costosas. Como requisito previo, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea desde un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas.

Construcción del proyecto Sikki

Para el proyecto Building Sikki, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Registre los tiempos y costos junto con los resultados funcionales. Tener visibilidad desde el principio evita facturas inesperadas cuando el proceso pasa de la fase de demostración a entornos compartidos. Realice un punto de control después de llamadas al modelo costosas, para que una repetición no genere nuevos costos por el mismo trabajo.

Paso 1: Crear el proyecto

Para el Paso 1: Crear el proyecto, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben encontrarse en un lugar que los operadores puedan auditar sin necesidad de leer todo el sistema. Coloque un punto de control después de las llamadas al modelo costosas para que una repetición no genere nuevos costos por el mismo trabajo.

mkdir sikki-agent
cd sikki-agent
npm init -y
npm pkg set type=module
npm install playwright

npm install @google/genai
npm install dotenv
npm install chalk
npm install ora
sikki-agent
 index.js
 .env
 screenshots/
 reports/
 package.json

Paso 2: Obtener la clave API de Gemini

Para el Paso 2: Obtener la clave API de Gemini, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Coloque un punto de control después de las llamadas al modelo costosas para que un reintento no genere nuevos costos por el mismo trabajo. Para el Paso 2: Obtener la clave API de Gemini, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas.

GEMINI_API_KEY = your_gemini_api_key
BRIGHT_WS_ENDPOINT = //i will show you later

Paso 3: Configurar la infraestructura del navegador Bright Data Cloud

En el Paso 3: Configurar la infraestructura del navegador Bright Data Cloud, se deben definir los parámetros de entrada, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Se deben registrar los tiempos y costos junto con los resultados funcionales. Tener visibilidad temprana evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Es necesario separar la planificación de la ejecución de las herramientas: el planificador propone, el ejecutor realiza los cambios y el verificador comprueba los resultados en relación con el objetivo.

BRIGHT_WS_ENDPOINT = "your_endpoint"
chromium.launch()
chromium.connectOverCDP()

Paso 4: Conectar Playwright con Bright Data

Para el paso 4: Conectar Playwright con Bright Data, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso desde un punto de control conocido sin tener que adivinar el estado oculto. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben encontrarse en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema. Separe la planificación de la ejecución de las herramientas. El planificador propone; el ejecutor realiza los cambios; el verificador comprueba los resultados en relación con el objetivo.

import { chromium }
from "playwright";

const BRIGHT_WS_ENDPOINT = "your_endpoint"

const browser =
await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT
);

const page =
await browser.newPage();
await page.goto(
"https://cnn.com"
);

console.log(
await page.title()
);

Profundizando en SIKKI Agent antes de la implementación

Para profundizar en SIKKI Agent antes de la implementación, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Separe la planificación de la ejecución de la herramienta. El planificador propone; el ejecutor modifica; el verificador comprueba los resultados en relación con el objetivo. Para profundizar en SIKKI Agent antes de la implementación, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las soluciones parciales silenciosas.

< p>Finalización.

SIKKI no es un raspador

En el caso de SIKKI no es un raspador, se deben definir las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea desde un punto de control conocido sin tener que adivinar el estado oculto. Se deben registrar los tiempos y costos junto con los resultados funcionales. La visibilidad temprana evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Los esquemas de las herramientas deben estar estrictamente delimitados. Los argumentos de texto libre amplios invitan a inyecciones y hacen que las auditorías sean costosas.

ProductPriceAcer Nitro V$899ASUS TUF$949MSI Thin$979

La arquitectura detrás de SIKKI

Para la arquitectura detrás de SIKKI, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan realizar auditorías sin necesidad de leer todo el sistema. Delimite estrictamente los esquemas de las herramientas. Los argumentos de texto libre amplios invitan a inyecciones y hacen que las auditorías sean costosas.

SIKKI

Strategic Intelligence Commerce Kernel

┌──────────────────────────────┐
│ Browser Layer                │
│ Playwright + Bright Data     │
└──────────────────────────────┘
                │
                ▼
┌──────────────────────────────┐
│ Extraction Layer             │
│ Product                      │
│ Price                        │
│ Rating                       │
│ Seller                       │
│ Availability                 │
└──────────────────────────────┘
                │
                ▼
┌──────────────────────────────┐
│ AI Layer                     │
│ Gemini                       │
└──────────────────────────────┘
                │
                ▼
┌──────────────────────────────┐
│ Analysis Layer               │
│ Cheapest Products            │
│ Market Average               │
│ Competitor Comparison        │
│ Trend Analysis               │
└──────────────────────────────┘
                │
                ▼
        Markdown / CSV
        Dashboard Export

Construyendo la capa de extracción

Para construir la capa de extracción, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Delimite estrictamente los esquemas de las herramientas. Los argumentos de texto libre amplios invitan a inyecciones y hacen que las auditorías sean costosas. Para construir la capa de extracción, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.

const products = await page.evaluate(() => {const items = [];
    document.querySelectorAll('[data-component-type="s-search-result"]')
      .forEach(card => {
        const title =
          card.querySelector('h2 span')?.innerText;
        const price =
          card.querySelector('.a-price .a-offscreen')
          ?.innerText;
        const rating =
          card.querySelector('.a-icon-alt')
          ?.innerText;
        const link =
          card.querySelector('h2 a')
          ?.href;
        if(title && price){
            items.push({
                title,
                price,
                rating,
                link
            });
        }
    });
    return items;
});
console.log(products);
[
 {
   title: "Acer Nitro V Gaming Laptop",
   price: "$899",
   rating: "4.5 out of 5 stars",
   link: "https://..."
 },

{
   title: "ASUS TUF Gaming A15",
   price: "$949",
   rating: "4.4 out of 5 stars",
   link: "https://..."
 }
]

Dándole un cerebro a SIKKI

Para dotar a SIKKI de capacidad de razonamiento, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Registre los tiempos y costos junto con los resultados funcionales. Tener visibilidad desde el principio evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Coloque un punto de control después de llamadas al modelo costosas, para que una repetición no genere nuevos costos por el mismo trabajo.

const prompt = `You are an ecommerce analyst.
Analyze the following products.
${JSON.stringify(products)}
Return:
1. Cheapest product
2. Average price
3. Best rated product
4. Summary of the market
5. Recommendation
`;

Construyendo el agente final de SIKKI

Para crear el agente SIKKI final, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema.

Paso 1: Crear el archivo del agente

Para el Paso 1: Cree el archivo del agente, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Realice un punto de control después de llamadas al modelo costosas para que un reintento no genere nuevos costos por el mismo trabajo. Para el Paso 1: Cree el archivo del agente, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas.

import "dotenv/config"; //to use environment variables from .env file
import fs from "fs"; //to read and write files

import { chromium } from "playwright";
import { GoogleGenAI } from "@google/genai";


//api keys and endpoints from environment variables
const BRIGHT_WS_ENDPOINT = process.env.BRIGHT_WS_ENDPOINT;
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
//initialize the GoogleGenAI client with the Gemini API key

const ai = new GoogleGenAI({
  apiKey: GEMINI_API_KEY,
});

//the prompt to send to the Gemini API
const prompt = "Write a short introduction to the Gemini API.";

const response = await ai.models.generateContent({
  model: "gemini-2.5-flash",
  contents: prompt,
});

console.log(response.text);

Paso 2: Configurar Playwright para conectarse al WebSocket de Bright Data

En el Paso 2: Configurar Playwright para conectarse al WebSocket de Bright Data, se deben definir los datos de entrada, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Se deben registrar los tiempos y costos junto con los resultados funcionales. Tener visibilidad temprana evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Es necesario separar la planificación de la ejecución de las herramientas: el planificador propone; el ejecutor realiza los cambios; el verificador comprueba los resultados en relación con el objetivo.

//setup Playwright to connect to Bright Data's WebSocket endpoint and navigate to Amazon search results for "gaming laptop"
async function main(){
  const browser = await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT);
  const page = await browser.newPage();

  const query = "gaming laptop";
  const searchUrl = `https://www.amazon.com/s?k=${encodeURIComponent(query)}`;

  console.log("Navigating Bright Data Playwright to:", searchUrl);
  await page.goto(searchUrl, { waitUntil: "domcontentloaded" });

  const title = await page.title();
  console.log("Amazon search page title:", title);
  console.log("Bright Data navigation complete for query:", query);

  await browser.close();
}

main();

Paso 3: Extraer información del producto

Para el Paso 3: Extraer información del producto, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema. Separe la planificación de la ejecución de las herramientas. El planificador propone; el ejecutor realiza los cambios; el verificador comprueba los resultados en relación con el objetivo.

// Playwright to connect to Bright Data's WebSocket endpoint and navigate to Amazon search results for "gaming laptop"
async function main(){
  const browser = await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT);
  const page = await browser.newPage();

  const query = "gaming laptop";
  const searchUrl = `https://www.amazon.com/s?k=${encodeURIComponent(query)}`;

  console.log("Navigating Bright Data Playwright to:", searchUrl);
  await page.goto(searchUrl, { waitUntil: "domcontentloaded" });

  const products = await page.evaluate(() => {
    const data = [];
    document
      .querySelectorAll('[data-component-type="s-search-result"]')
      .forEach((card) => {
        const title = card.querySelector("h2 span")?.innerText;
        const price = card.querySelector(".a-price .a-offscreen")?.innerText;
        const rating = card.querySelector(".a-icon-alt")?.innerText;
        if (title && price) {
          data.push({
            title,
            price,
            rating,
          });
        }
      });
    return data;
  });

  console.log("Step 3: Extract Product Information");
  console.log(products);

  const title = await page.title();
  console.log("Amazon search page title:", title);
  console.log("Bright Data navigation complete for query:", query);

  await browser.close();
}

main();

Paso 4: Pedir a Gemini que analice el mercado

Para el Paso 4: Pedir a Gemini que analice el mercado, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Separe la planificación de la ejecución de las herramientas. El planificador propone; el ejecutor realiza los cambios; el verificador comprueba los resultados en relación con el objetivo. Para el Paso 4: Pedir a Gemini que analice el mercado, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.

const prompt = `You are an ecommerce analyst.
Analyze these products:
${JSON.stringify(products)}
Return:
1. Cheapest Product
2. Average Market Price
3. Best Rated Product
4. Competitor Comparison
5. Final Recommendation
`;
const result = await model.generateContent(prompt);
const analysis =
result.response.text();
### 3. Best Rated Product
There are three products tied for the highest rating of **5.0 out of 5 stars**:
1.  **HP OMEN 16" Gaming Laptop Computer** (Intel Ultra 9 285H, NVIDIA GeForce RTX 5070 8GB, 16GB DDR5, 1TB PCIe SSD, 144Hz IPS WUXGA Display) at **$1,745.99**
2.  **HP OMEN 16 Slim RTX 5070 Gaming Laptop** (Intel Ultra 9 285H, NVIDIA RTX 5070, 32GB DDR5, 1TB SSD, 16" FHD+ Anti-Glare) at **$1,929.00**
3.  **ASUS ROG Strix G16 Gaming Laptop** (Intel Core i7 14650HX, NVIDIA RTX 5060, 32 GB DDR5 RAM, 1 TB SSD, 16" FHD+ LED Display, & Gaming Accessories) at **$1,999.99**

**Analysis:** It's noteworthy that two HP OMEN laptops achieved perfect ratings, both featuring high-end Ultra 9 CPUs and RTX 5070 GPUs.
This suggests strong customer satisfaction with HP's premium gaming line.
The ASUS ROG Strix G16 also achieved a 5.0 rating,
despite having a slightly lower-tier GPU (RTX 5060) than the
HP OMENs in this bracket, possibly due to the included
"Gaming Accessories" and overall perceived value.
The Alienware product has no rating, so it cannot be considered here.

Paso 5: Exportar el informe del mercado Sikki

Para el Paso 5: Exportar el informe del mercado Sikki, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos y costos junto con los resultados funcionales. La visibilidad temprana evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Asegúrese de que los esquemas de las herramientas estén estrictamente definidos; los argumentos de texto libre excesivos facilitan inyecciones y encarecen las auditorías.

const report = `
# SIKKI Market Report
## Search Query
${query}

## Products
${JSON.stringify(products, null, 2)}

## Gemini Analysis
${analysis}

Generated: ${new Date().toISOString()}
`;

fs.writeFileSync(reportPath, report, "utf8");
import "dotenv/config"; // use environment variables from .env file
import fs from "fs";

import { chromium } from "playwright";
import { GoogleGenAI } from "@google/genai";

const BRIGHT_WS_ENDPOINT = process.env.BRIGHT_WS_ENDPOINT;
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;

if (!BRIGHT_WS_ENDPOINT) {
  throw new Error("Missing BRIGHT_WS_ENDPOINT environment variable.");
}

if (!GEMINI_API_KEY) {
  throw new Error("Missing GEMINI_API_KEY environment variable.");
}

const ai = new GoogleGenAI({
  apiKey: GEMINI_API_KEY,
});

async function retryWithBackoff(fn, maxRetries = 5, initialDelayMs = 2000) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      return await fn();
    } catch (error) {
      const errorMsg = error?.message || error?.status || JSON.stringify(error);
      if (attempt === maxRetries) {
        console.error(`Final attempt failed. Error: ${errorMsg}`);
        throw error;
      }
      const delayMs = initialDelayMs * Math.pow(2, attempt - 1);
      console.log(`Attempt ${attempt} failed: ${errorMsg}`);
      console.log(`Retrying in ${delayMs}ms... (${attempt}/${maxRetries})`);
      await new Promise((resolve) => setTimeout(resolve, delayMs));
    }
  }
}

async function main() {
  let browser;
  try {
    browser = await chromium.connectOverCDP(BRIGHT_WS_ENDPOINT);
    const page = await browser.newPage();

    const query = "gaming laptop";
    const searchUrl = `https://www.amazon.com/s?k=${encodeURIComponent(query)}`;

    console.log("Connecting Playwright to Bright Data...");
    console.log("Navigating to:", searchUrl);

    await page.goto(searchUrl, { waitUntil: "domcontentloaded" });

    const products = await page.evaluate(() => {
      const data = [];
      document
        .querySelectorAll('[data-component-type="s-search-result"]')
        .forEach((card) => {
          const title = card.querySelector("h2 span")?.innerText;
          const price = card.querySelector(".a-price .a-offscreen")?.innerText;
          const rating = card.querySelector(".a-icon-alt")?.innerText;
          if (title && price) {
            data.push({
              title,
              price,
              rating,
            });
          }
        });
      return data;
    });

    console.log(`Extracted ${products.length} products.`);

    const analysisPrompt = `You are an ecommerce analyst.
Analyze these products:
${JSON.stringify(products)}
Return:
1. Cheapest Product
2. Average Market Price
3. Best Rated Product
4. Competitor Comparison
5. Final Recommendation
`;

    console.log("Sending products to Gemini for analysis (with retry logic)...");
    const analysisResult = await retryWithBackoff(async () => {
      return await ai.models.generateContent({
        model: "gemini-2.5-flash",
        contents: analysisPrompt,
      });
    }, 5, 2000);

    const analysis = analysisResult.text || "No analysis text returned.";

    const report = `# SIKKI Market Report

## Search Query
${query}

## Products
${JSON.stringify(products, null, 2)}

## Gemini Analysis
${analysis}

Generated: ${new Date().toISOString()}
`;

    fs.writeFileSync("sikki-report.md", report, "utf8");

    console.log("Step 5: Export the Results");
    console.log("Report generated: sikki-report.md");
    console.log("Final analysis saved. Open sikki-report.md to review the result.");

    await browser.close();
  } catch (error) {
    console.error("Error:", error.message || error);
    if (browser) {
      await browser.close().catch(() => {});
    }
    process.exit(1);
  }
}

main();

Paso 6: Enseñar a SIKKI a capturar evidencias

Para el Paso 6: Enseñar a SIKKI a capturar evidencias, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso desde un punto de control conocido sin tener que adivinar el estado oculto. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben encontrarse en un lugar donde los operadores puedan realizar auditorías sin necesidad de leer todo el sistema. Delimite estrictamente los esquemas de las herramientas. Los argumentos de texto libre amplios invitan a inyecciones y hacen que las auditorías sean costosas.

const searchScreenshot = path.join(screenshotDir, "search-results.png");
await page.screenshot({ path: searchScreenshot, fullPage: true });
const summaryPath = path.join(screenshotDir, "top-product-summary.png");
await cards[0].screenshot({ path: summaryPath });

Paso 7: Capturar cada página de producto

Para el Paso 7: Capturar cada página del producto, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso desde un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Vincule estrictamente los esquemas de las herramientas. Los argumentos de texto libre amplios invitan a inyecciones y hacen que las auditorías sean costosas. Para el Paso 7: Capturar cada página del producto, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso desde un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.

const normalized = normalizeAmazonUrl(p.url, p.title);
await retryWithBackoff(async () =>
 await page.goto(normalized, { waitUntil: "domcontentloaded", timeout: 120000 }),
 3,
 1500
);
await page.waitForTimeout(800);
await page.screenshot({ path: outPath, fullPage: true });

Paso 8: Crear una exportación en CSV

Para el paso 8: Crear una exportación en CSV, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos y costos junto con los resultados funcionales. La visibilidad temprana evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos. Coloque un punto de control después de llamadas al modelo costosas para que una repetición no genere nuevos costos por el mismo trabajo.

const csvLines = ["TITLE,PRICE,RATING,URL"];
enriched.forEach((p) => {
 const safe = (s) => `"${String(s || "").replace(/"/g, '""')}"`;
 csvLines.push([safe(p.title), safe(p.price), safe(p.rating || ""), safe(p.url || "")].join(","));
});
fs.writeFileSync(csvPath, csvLines.join("\n"), "utf8");

Paso 9: Generar un resumen en el panel de control

Para el paso 9: Generar un resumen del panel de control, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben encontrarse en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Coloque un punto de control después de las llamadas al modelo costosas para que una repetición no genere nuevos costos por el mismo trabajo.

const priced = enriched.filter((p) => !isNaN(p.priceValue));
const cheapestObj = priced.length ? priced.reduce((a, b) => (a.priceValue <= b.priceValue ? a : b)) : null;
const avgPriceVal = priced.length ? (priced.reduce((s, p) => s + p.priceValue, 0) / priced.length).toFixed(2) : “N/A”;
const bestRatedObj = enriched.slice().sort((a, b) => {
 const ra = parseFloat((a.rating || “”).split(“ “)[0]) || 0;
 const rb = parseFloat((b.rating || “”).split(“ “)[0]) || 0;
 return rb — ra;
})[0] || null;
const dashboard = [];
dashboard.push(“==================================”);
dashboard.push(“SIKKI MARKET DASHBOARD”);
dashboard.push(“==================================”);
dashboard.push(`Query: ${query}`);
dashboard.push(`Products Extracted: ${enriched.length}`);
dashboard.push(`Cheapest Product: ${cheapestObj ? `${cheapestObj.title} | ${cheapestObj.price}` : “N/A”}`);
dashboard.push(`Average Price: ${avgPriceVal === “N/A” ? “N/A” : `${avgPriceVal}`}`);
dashboard.push(`Best Rated: ${bestRatedObj ? `${bestRatedObj.title} | ${bestRatedObj.rating || “N/A”}` : “N/A”}`);
dashboard.push(“\nTop 5 Products:”);
enriched.slice(0, 5).forEach((p, i) => {
 dashboard.push(`${i + 1}. ${p.title} | ${p.price} | ${p.rating || “N/A”} | ${p.url || “N/A”}`);
});
fs.writeFileSync(dashboardPath, dashboard.join(“\n”), “utf8”);

A dónde ir a continuación

Para determinar el siguiente paso a seguir, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las intentonas, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Realice un punto de control después de llamadas costosas al modelo para que una nueva intentona no genere nuevos costos por el mismo trabajo. Para determinar el siguiente paso a seguir, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea a partir de un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina verificaciones de éxito y rechace las completaciones parciales silenciosas.

Conclusión

Como conclusión, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea a partir de un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos y costos junto con los resultados funcionales. Tener visibilidad desde el principio evita facturas inesperadas cuando la tarea pasa de un entorno de demostración a uno compartido. Separe la planificación de la ejecución de las herramientas: el planificador propone; el ejecutor realiza los cambios; el verificador comprueba los resultados en relación con el objetivo.

Lista de verificación operativa

Para la lista de verificación operativa, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea a partir de un punto de control conocido sin tener que adivinar el estado oculto.

Prefiera unidades pequeñas y probables sobre scripts extensos. Cuando una tarea falla, el error debe indicar una única responsabilidad y no un proceso complicado.

Punto de control después de las llamadas a modelos costosos para que un intento de repetición no vuelva a facturar el mismo trabajo.

Comprenda los límites del bucle de eventos: qué bloquea el hilo y qué espera en el kernel.

Escriba un manual breve: cómo rotar claves, cómo vaciar la cola y cómo revertir el último cambio.

Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un único lugar que los operadores puedan auditar sin tener que leer todo el sistema.

Antes de promocionar la pila, congele las versiones, capture una transcripción de referencia para la ruta crítica y confirme los pasos de reversión. Los entornos compartidos necesitan límites de velocidad, verificaciones de tenencia y un responsable claro para la rotación de secretos. Prefiera una fiabilidad sencilla a demostraciones ingeniosas pero puntuales.

Lecturas relacionadas