# Consejos para escribir expresiones XPath

## La estructura HTML puede diferir entre el documento extraído y el cargado por el navegador <a href="#html-structure-may-differ-between-scraped-and-browser-loaded-document" id="html-structure-may-differ-between-scraped-and-browser-loaded-document"></a>

Al escribir funciones de selección de elementos HTML, **asegúrate de trabajar con documentos extraídos en lugar de la versión del sitio web en vivo cargada en tu navegador**ya que los documentos pueden diferir. La razón principal de este problema es la renderización de JavaScript. Cuando se abre un sitio web, tu navegador se encarga de cargar documentos adicionales, como hojas de estilo CSS y scripts de JavaScript, que pueden cambiar la estructura del documento HTML inicial. Al analizar HTML extraído, Custom Parser no carga el documento HTML de la misma manera que lo hacen los navegadores (los analizadores ignoran las instrucciones de JavaScript), por lo que el árbol HTML puede diferir entre lo que renderiza el analizador y el navegador.

Como ejemplo, mira el siguiente documento HTML:

```html
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div>
        <h3>Este es un producto</h3>
        <div id="price-container">
            <p>Este es el precio:</p>
        </div>
        <p>Y aquí hay una descripción</p>
    </div>
    <script>
        const priceContainer = document.querySelector("#price-container");
        const priceElement = document.createElement("p");
        priceElement.textContent = "123";
        priceElement.id = "price"
        priceContainer.insertAdjacentElement("beforeend", priceElement);
    </script>
</body>
</html>
```

Si abres el documento en el navegador, mostrará el precio que puedes seleccionar usando la siguiente expresión XPath `//p[@id="price"]`:

<figure><img src="/files/7925517b506e4063cf7bf4e3eb564eb6a72f9e36" alt=""><figcaption></figcaption></figure>

Ahora, si desactivas la renderización de JavaScript en el navegador, el sitio web se renderizará de la siguiente manera:

<figure><img src="/files/3881e7ad91178acdee931d99746a420272b1a07d" alt=""><figcaption></figcaption></figure>

El mismo `//p[@id="price"]` la expresión XPath ya no coincide con el precio, ya que no se renderiza.

## Asegúrate de escribir todos los selectores HTML posibles para el elemento objetivo <a href="#make-sure-to-write-all-possible-html-selectors-for-the-target-element" id="make-sure-to-write-all-possible-html-selectors-for-the-target-element"></a>

Por varias razones, la misma página extraída dos veces puede tener diseños diferentes (distintos User Agents usados al extraer, pruebas A/B realizadas por el sitio web objetivo, etc.).

Para abordar este problema, sugerimos definir `parsing_instructions` para el documento extraído inicialmente y probar estas instrucciones de inmediato con varios otros resultados de trabajos extraídos de la misma página.

Las funciones de selección HTML (`xpath`/`xpath_one`) admiten [**alternativas de selector**](/products/es/web-scraper-api/features/custom-parser/writing-instructions-manually/list-of-functions/function-examples.md#xpath).

## Flujo sugerido para escribir selectores HTML <a href="#suggested-html-selector-writing-flow" id="suggested-html-selector-writing-flow"></a>

1. Extrae el documento HTML de la página objetivo usando Scraper API.
2. Desactiva JavaScript y abre localmente el HTML extraído en tu navegador. Si JavaScript está desactivado **después** de abrir el HTML, asegúrate de recargar la página para que el HTML pueda cargarse de nuevo sin JavaScript.
3. [**Usa las herramientas de desarrollo del navegador**](https://www.computerhope.com/issues/ch002153.htm).

<figure><img src="/files/bbabfd0fd6dbc37e4b0eb021c80a19f25d6dfefd" alt=""><figcaption></figcaption></figure>

### Cómo escribir instrucciones de análisis  <a href="#how-to-write-parsing-instructions-inlineextension" id="how-to-write-parsing-instructions-inlineextension"></a>

Supongamos que tienes la siguiente página para analizar:

```html
`<!doctype html>
<html lang="en">
<head></head>
<body>
<style>
.variant {
  display: flex;
  flex-wrap: nowrap;
}
.variant p {
  white-space: nowrap;
  margin-right: 20px;
}
</style>
<div>
    <h1 id="title">Este es un producto genial</h1>
    <div id="description-container">
        <h2>Esta es una descripción del producto</h2>
        <ul>
            <li class="description-item">Duradero</li>
            <li class="description-item">Bonitos</li>
            <li class="description-item">Dulce</li>
            <li class="description-item">Picante</li>
        </ul>
    </div>
    <div id="price-container">
        <h2>Variantes</h2>
        <div id="variants">
            <div class="variant">
                <p class="color">Rojo</p>
                <p class="price">99.99</p>
            </div>
            <div class="variant">
                <p class="color">Verde</p>
                <p class="price">87.99</p>
            </div>
            <div class="variant">
                <p class="color">Azul</p>
                <p class="price">65.99</p>
            </div>
            <div class="variant">
                <p class="color">Negro</p>
                <p class="price">99.99</p>
            </div>
        </div>
    </div>
</div>
</body>
</html>
```

<figure><img src="/files/9d2d3944e520eadfd877bd64842d76ff39cc7180" alt=""><figcaption></figcaption></figure>

### Analizar el título del producto

Crea un nuevo objeto JSON y asígnale un nuevo campo.

Puedes nombrar el campo como prefieras con algunas excepciones (el nombre de campo definido por el usuario no puede comenzar con un guion bajo `_` , por ejemplo, `"_title"`).&#x20;

El nombre del campo se mostrará en el resultado analizado.

El nuevo campo debe contener un valor de tipo objeto JSON:

```json
{
    "title": {}  // definiendo un campo title para analizar
} 
```

Si proporcionas estas instrucciones a Custom Parser, no hará nada o enviará una queja de que no has proporcionado ninguna instrucción.

Para analizar realmente el título en el `title` campo, debes definir una canalización de procesamiento de datos dentro del `title` objeto usando la `_fns` propiedad reservada (que siempre es de tipo array):

```json
{
    "title": {
        "_fns": []  // definiendo la canalización de procesamiento de datos para el campo title
    }
}
```

Para que Custom Parser seleccione el texto del título, puedes utilizar la función de selección HTML `xpath_one`. Para usar la función en el documento HTML, debe agregarse a la canalización de procesamiento de datos. La función se define como un objeto JSON con `_fn` obligatorio (nombre de la función) y `_args` obligatorios (argumentos de la función). Consulta la lista completa de definiciones de funciones [**aquí**](/products/es/web-scraper-api/features/custom-parser/writing-instructions-manually/list-of-functions.md).

```json
{
    "title": {
        "_fns": [
            {
                "_fn": "xpath_one",
                "_args": ["//h1/text()"]
            }
        ]
    }
}
```

Las instrucciones de análisis anteriores deberían producir el siguiente resultado:

```json
{
    "title": "Este es un producto genial"
}
```

### Analizar descripción

De manera similar, en las instrucciones de análisis, puedes definir otro campo donde se analizarán el contenedor de la descripción del producto, el título de la descripción y los elementos. Para que el título y los elementos de la descripción queden anidados bajo el `description` objeto, la estructura de las instrucciones debe ser la siguiente:

```json
{
    "title": {...},
    "description": { // contenedor de la descripción
        "title": {}, // título de la descripción
        "items": {} // elementos de la descripción
    } 
}
```

La estructura dada de las instrucciones de análisis implica que `description.title` y `description.items` se analizarán basándose en el `description` elemento. Puedes definir una canalización para el `description` campo. En este caso, se hace primero porque simplificará la expresión XPath del título de la descripción.

```json
{
    "title": {...},
    "description": {
        "_fns": [
            {
                "_fn": "xpath_one",
                "_args": ["//div[@id='description-container']"]
            }
        ],  // El resultado de la canalización se usará al analizar `title` y `items`.
        "title": {},
        "items": {}
    }
}
```

En el ejemplo, la `description._fns` canalización seleccionará el `description-container` elemento HTML, que se usará como punto de referencia para analizar el título y los elementos de la descripción.

Para analizar los campos restantes de la descripción, añade dos canalizaciones diferentes para los campos `description.items`, y `description.title`:

```json
{
    "title": {...},
    "description": {
        "_fns": [
            {
                "_fn": "xpath_one",
                "_args": [
                    "//div[@id='description-container']"
                ]
            }
        ],
        "title": {
            "_fns": [
                {
                    "_fn": "xpath_one",
                    "_args": [
                        "//h2/text()"
                    ]
                }
            ]
        },
        "items": {
            "_fns": [
                {
                    "_fn": "xpath",
                    "_args": [
                        "//li/text()"
                    ]
                }
            ]
        }
    }
}
```

Observa cómo la `xpath` la función se usa en lugar de `xpath_one` para extraer todos los elementos que coinciden con la expresión XPath.

Las instrucciones de análisis producen el siguiente resultado:

```json
{
    "title": {...},
    "description": {
        "title": "Esta es una descripción del producto",
        "items": [
            "Duradero",
            "Nice",
            "Dulce",
            "Picante"
        ]
    }
}
```

### Analizar variantes del producto

El siguiente ejemplo muestra la estructura de las instrucciones si quieres analizar información en el `product_variants` campo, que contendrá una lista de objetos de variante. En este caso, el objeto de variante tiene campos `price` y `color` .

```json
{
    "title": {...},
    "description": {...},
    "product_variants": [
        {
            "price": ...,
            "color": ...
        },
        {
            ...
        },
        ...
    ]
}
```

Empieza seleccionando todos los elementos de variantes del producto:

```json
{
    "title": {...},
    "description": {...},
    "product_variants": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": ["//div[@class='variant']"]
            }
        ]
    }
}
```

Para convertir `product_variants` en una lista que contiene objetos JSON, tendrás que iterar sobre las variantes encontradas usando `_items` el iterador:

```json
{
    "title": {...},
    "description": {...},
    "product_variants": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": ["//div[@class='variant']"]
            }
        ],
        "_items": { // con esto, estás indicando que se procesen los elementos encontrados uno por uno
            // las instrucciones del campo se describirán aquí
        } 
    }
}
```

Por último, define las instrucciones sobre cómo analizar los `color` y `price` campos:

```json
{
    "title": {...},
    "description": {...},
    "product_variants": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": [
                    "//div[@class='variant']"
                ]
            }
        ],
        "_items": {
            "color": {
                "_fns": [
                    {
                        "_fn": "xpath_one",
                        "_args": [
                            // Como estamos usando expresiones XPath relativas,
                            // asegúrate de que XPath comience con un punto (.)
                            ".//p[@class='color']/text()"
                        ]
                    }
                ]
            },
            "price": {
                "_fns": [
                    {
                        "_fn": "xpath_one",
                        "_args": [
                            ".//p[@class='price']/text()"
                        ]
                    }
                ]
            }
        }
    }
}
```

Con `product_variants` descrito, las instrucciones finales se verán así:

```json
{
    "title": {
        "_fns": [
            {
                "_fn": "xpath_one",
                "_args": [
                    "//h1/text()"
                ]
            }
        ]
    },
    "description": {
        "_fns": [
            {
                "_fn": "xpath_one",
                "_args": [
                    "//div[@id='description-container']"
                ]
            }
        ],
        "title": {
            "_fns": [
                {
                    "_fn": "xpath_one",
                    "_args": [
                        "//h2/text()"
                    ]
                }
            ]
        },
        "items": {
            "_fns": [
                {
                    "_fn": "xpath",
                    "_args": [
                        "//li/text()"
                    ]
                }
            ]
        }
    },
    "product_variants": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": [
                    "//div[@class='variant']"
                ]
            }
        ],
        "_items": {
            "color": {
                "_fns": [
                    {
                        "_fn": "xpath_one",
                        "_args": [
                            ".//p[@class='color']/text()"
                        ]
                    }
                ]
            },
            "price": {
                "_fns": [
                    {
                        "_fn": "xpath_one",
                        "_args": [
                            ".//p[@class='price']/text()"
                        ]
                    }
                ]
            }
        }
    }
}
```

Lo que producirá el siguiente resultado:

```json
{
    "title": "Este es un producto genial",
    "description": {
        "title": "Esta es una descripción del producto",
        "items": [
            "Duradero",
            "Nice",
            "Dulce",
            "Picante"
        ]
    },
    "product_variants": [
        {
            "color": "Rojo",
            "price": "99.99"
        },
        {
            "color": "Verde",
            "price": "87.99"
        },
        {
            "color": "Azul",
            "price": "65.99"
        },
        {
            "color": "Negro",
            "price": "99.99"
        }
    ]
}
```

Puedes encontrar más ejemplos de instrucciones de análisis aquí: [**Ejemplos de instrucciones de análisis**](/products/es/web-scraper-api/features/custom-parser/writing-instructions-manually/parsing-instruction-examples.md).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://developers.oxylabs.io/products/es/web-scraper-api/features/custom-parser/writing-instructions-manually/tips-for-writing-xpath-expressions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
