# Renderizado de JS y control del navegador

## Renderizado de JavaScript

Si la página que desea extraer requiere JavaScript para cargar dinámicamente todos los datos necesarios en el DOM, puede incluir un `render` parámetro en sus solicitudes en lugar de configurar y usar manualmente instrucciones personalizadas del navegador. Las solicitudes con este parámetro se renderizarán por completo y los datos se almacenarán en un archivo HTML o en una captura PNG, según el parámetro especificado.

### HTML

Establezca el `render` parámetro para `html` para obtener la salida sin procesar de la página renderizada.

### PNG (Captura de pantalla)

Establezca el `render` parámetro para `png` para obtener una captura de pantalla codificada en Base64 de la página renderizada.

{% hint style="info" %}
Si desea extraer una imagen y descargarla, consulte [**esta sección**](/products/es/web-scraper-api/features/result-processing-and-storage/output-types/download-images.md)**.**
{% endhint %}

### Solicitar ejemplo

{% tabs %}
{% tab title="cURL" %}

```shell
curl --user "user:pass" \
'https://realtime.oxylabs.io/v1/queries' \\
-H "Content-Type: application/json" \
-d '{"source": "universal", "url": "https://www.example.com", "render": "html"}'
```

{% endtab %}

{% tab title="Python" %}

```python
import requests
from pprint import pprint

# Structure payload.
payload = {
    'source': 'universal',
    'url': 'https://www.example.com',
    'render': 'html',
}

# Get response.
response = requests.request(
    'POST',
    'https://realtime.oxylabs.io/v1/queries',
    auth=('user', 'pass1'),
    json=payload,
)

# En lugar de una respuesta con el estado del trabajo y la URL de resultados, esto devolverá la
# respuesta JSON con el resultado.
pprint(response.json())
```

{% endtab %}

{% tab title="PHP" %}

```php
<?php

$params = [
    'source' => 'universal',
    'url' => 'https://www.example.com',
    'render' => 'html',
];

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "https://realtime.oxylabs.io/v1/queries");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_USERPWD, "user" . ":" . "pass1");

$headers = array();
$headers[] = "Content-Type: application/json";
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($ch);
echo $result;

if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
}
curl_close($ch);
```

{% endtab %}

{% tab title="C#" %}

```csharp
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Json;
using System.Threading.Tasks;

namespace OxyApi
{
    class Program
    {
        static async Task Main()
        {
            const string Username = "YOUR_USERNAME";
            const string Password = "YOUR_PASSWORD";

            var parameters = new Dictionary<string, string>()
            {
                { "source", "universal" },
                { "url", "https://www.example.com" },
                { "render" : "html" },
            };


            var client = new HttpClient();

            Uri baseUri = new Uri("https://realtime.oxylabs.io");
            client.BaseAddress = baseUri;

            var requestMessage = new HttpRequestMessage(HttpMethod.Post, "/v1/queries");
            requestMessage.Content = JsonContent.Create(parameters);

            var authenticationString = $"{Username}:{Password}";
            var base64EncodedAuthenticationString = Convert.ToBase64String(System.Text.ASCIIEncoding.UTF8.GetBytes(authenticationString));
            requestMessage.Headers.Add("Authorization", "Basic " + base64EncodedAuthenticationString);

            var response = await client.SendAsync(requestMessage);
            var contents = await response.Content.ReadAsStringAsync();

            Console.WriteLine(contents);
        }
    }
}
```

{% endtab %}

{% tab title="Golang" %}

```go
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	const Username = "YOUR_USERNAME"
	const Password = "YOUR_PASSWORD"

	payload := map[string]string{
		"source": "universal",
		"url": "https://www.example.com",
        	"render": "html",
	}

	jsonValue, _ := json.Marshal(payload)

	client := &http.Client{}
	request, _ := http.NewRequest("POST",
		"https://realtime.oxylabs.io/v1/queries",
		bytes.NewBuffer(jsonValue),
	)

	request.SetBasicAuth(Username, Password)
	response, _ := client.Do(request)

	responseText, _ := ioutil.ReadAll(response.Body)
	fmt.Println(string(responseText))
}
```

{% endtab %}

{% tab title="Java" %}

```java
package org.example;

import okhttp3.*;
import org.json.JSONObject;

public class Main implements Runnable {
    private static final String AUTHORIZATION_HEADER = "Authorization";
    public static final String USERNAME = "YOUR_USERNAME";
    public static final String PASSWORD = "YOUR_PASSWORD";

    public void run() {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("source", "universal");
        jsonObject.put("url", "https://www.example.com");
        jsonObject.put("render": "html");

        Authenticator authenticator = (route, response) -> {
            String credential = Credentials.basic(USERNAME, PASSWORD);

            return response
                    .request()
                    .newBuilder()
                    .header(AUTHORIZATION_HEADER, credential)
                    .build();
        };

        var client = new OkHttpClient.Builder()
                .authenticator(authenticator)
                .build();

        var mediaType = MediaType.parse("application/json; charset=utf-8");
        var body = RequestBody.create(jsonObject.toString(), mediaType);
        var request = new Request.Builder()
                .url("https://realtime.oxylabs.io/v1/queries")
                .post(body)
                .build();

        try (var response = client.newCall(request).execute()) {
            assert response.body() != null;
            System.out.println(response.body().string());
        } catch (Exception exception) {
            System.out.println("Error: " + exception.getMessage());
        }

        System.exit(0);
    }

    public static void main(String[] args) {
        new Thread(new Main()).start();
    }
}
```

{% endtab %}

{% tab title="Node.js" %}

```javascript
import fetch from 'node-fetch';

const username = 'YOUR_USERNAME';
const password = 'YOUR_PASSWORD';
const body = {
  'source': 'universal',
  'url': 'https://www.example.com',
  'render': 'html'
};
const response = await fetch('https://realtime.oxylabs.io/v1/queries', {
  method: 'post',
  body: JSON.stringify(body),
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Basic ' + Buffer.from(`${username}:${password}`).toString('base64'),
  }
});

console.log(await response.json());
```

{% endtab %}

{% tab title="HTTP" %}

```http
# La cadena completa que envíes tiene que estar codificada en URL.

https://realtime.oxylabs.io/v1/queries?source=universal&url=https%3A%2F%2Fwww.example.com%2F&render=html&access_token=12345abcde
```

{% endtab %}

{% tab title="JSON" %}

```json
{
    "source": "universal", 
    "url": "https://www.example.com", 
    "render": "html"
}
```

{% endtab %}
{% endtabs %}

{% hint style="warning" %}
El renderizado de JavaScript tarda más en extraer la página. Establezca un timeout del lado del cliente en 180 segundos si usa los métodos de integración Realtime o Proxy Endpoint.
{% endhint %}

{% hint style="warning" %}
Para garantizar el menor consumo de tráfico, nuestro sistema no carga activos innecesarios durante el renderizado de la página.
{% endhint %}

## Forzar el renderizado en páginas específicas

Para una extracción exitosa, algunos tipos de páginas de dominios específicos requieren renderizado debido a su contenido dinámico. Nuestro sistema aplica automáticamente el renderizado para estas páginas, incluso si el usuario no lo establece explícitamente.

{% hint style="warning" %}
Tenga en cuenta que los trabajos renderizados consumen más tráfico que los trabajos no renderizados.
{% endhint %}

Queremos que nuestros usuarios sean plenamente conscientes de esto al extraer las siguientes páginas:

{% file src="/files/67dc18516d8938fed07497f121abb8d53cb4d8bf" %}

Este enfoque ofrece la mejor experiencia posible de extracción, garantizando la precisión y fiabilidad de los datos de estas páginas exigentes.&#x20;

Si desea desactivar el renderizado, puede hacerlo añadiendo el siguiente parámetro a sus solicitudes:

```
"render": ""
```

## Instrucciones del navegador

Puede definir sus propias instrucciones del navegador que se ejecutan al renderizar JavaScript.

{% hint style="success" %}
La forma más sencilla de configurar las instrucciones del navegador es usando el creador visual de instrucciones del navegador con IA en el [Web Scraper API Playground](https://dashboard.oxylabs.io/?route=/api-playground). Lea sobre ello [aquí](/products/es/web-scraper-api/web-scraper-api-playground/oxycopilot.md#browser-instruction-builder).
{% endhint %}

### Uso

Para usar instrucciones del navegador, proporciona un conjunto de `browser_instructions` al crear un trabajo.

Supongamos que quieres buscar el término `pizza boxes` en un sitio web.

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

Un ejemplo de los parámetros del trabajo sería el siguiente:

```json
{
    "source": "universal",
    "url": "https://www.ebay.com/",
    "render": "html",
    "browser_instructions": [
        {
            "type": "input",
            "value": "cajas para pizza",
            "selector": {
                "type": "xpath",
                "value": "//input[@class='gh-tb ui-autocomplete-input']"
            }
        },
        {
            "type": "click",
            "selector": {
                "type": "xpath",
                "value": "//input[@type='submit']"
            }
        },
        {
            "type": "wait",
            "wait_time_s": 5
        }
    ]
}
```

**Paso 1.** Debes proporcionar el `"render": "html"` parámetro.

**Paso 2.** Las instrucciones del navegador deben describirse en el campo `"browser_instructions"` .

Las instrucciones de navegador de ejemplo anteriores especifican que el objetivo es introducir un término de búsqueda `pizza boxes` en un campo de búsqueda, hacer clic en el botón `search` y esperar 5 segundos a que cargue el contenido.

El resultado extraído debería verse así:

```json
{
  "results": [
    {
      "content": "<!doctype html><html>
        Contenido después de ejecutar las instrucciones      
      </html>",
      "created_at": "2023-10-11 11:35:23",
      "updated_at": "2023-10-11 11:36:08",
      "page": 1,
      "url": "https://www.ebay.com/",
      "job_id": "7117835067442906113",
      "status_code": 200
    }
  ]
}
```

El HTML extraído debería verse así:

<figure><img src="/files/6572e2081885489deaa54ee69cc52995b054a9a4" alt=""><figcaption></figcaption></figure>

#### Obtener recursos del navegador <a href="#fetching-browser-resources" id="fetching-browser-resources"></a>

Proporcionamos una instrucción de navegador independiente para obtener recursos del navegador.

La función está definida aquí:

El uso del `fetch_resource` hará que el trabajo devuelva la primera aparición de un recurso Fetch/XHR que coincida con el formato proporcionado en lugar del HTML al que se dirige.

Supongamos que queremos apuntar a un recurso GraphQL que se obtiene al visitar una página de producto de forma orgánica en el navegador. Proporcionaremos la información del trabajo así:

```json
{
    "source": "universal",
    "url": "https://www.example.com/product-page/123",
    "render": "html",
    "browser_instructions": [
        {
            "type": "fetch_resource",
            "filter": "/graphql/product-info/123"
        }
    ]
}
```

Estas instrucciones darán como resultado algo así:

```json
{
  "results": [
    {
      "content": "{'product_id': 123, 'description': '', 'price': 123}",
      "created_at": "2023-10-11 11:35:23",
      "updated_at": "2023-10-11 11:36:08",
      "page": 1,
      "url": "https://example.com/v1/graphql/product-info/123/",
      "job_id": "7117835067442906114",
      "status_code": 200
    }
  ]
}
```

## Lista de instrucciones de navegador compatibles <a href="#list-of-supported-browser-instructions" id="list-of-supported-browser-instructions"></a>

### Argumentos generales

Todas las instrucciones definidas a continuación tienen un conjunto coherente de argumentos. Los argumentos son los siguientes.

#### `escribir` <a href="#type" id="type"></a>

* **Tipo**: `Enum["click", "input", "scroll", "scroll_to_bottom", "wait", "wait_for_element", "fetch_resource"]`
* **Descripción:** Tipo de instrucción del navegador.

#### `timeout_s` <a href="#timeout_s" id="timeout_s"></a>

* **Tipo**: `int`
* **Descripción:** Cuánto tiempo hasta que se omite la acción si no se completa a tiempo.
* **Restricciones**: 0 < `timeout_s` <= 60
* **Valor predeterminado**: 5

#### `wait_time_s` <a href="#wait_time_s" id="wait_time_s"></a>

* **Tipo**: `int`
* **Descripción:** Cuánto tiempo esperar antes de ejecutar la siguiente acción.
* **Restricciones**: 0 < `wait_time_s` <= 60
* **Valor predeterminado**: 0

#### `on_error` <a href="#on_error" id="on_error"></a>

* **Tipo**: `Enum["error", "skip"]`
* **Descripción:** Indicador de qué hacer con las instrucciones en caso de que esta instrucción falle:
  * `"error"`: Detiene la ejecución de las instrucciones del navegador.
  * `"skip"`: Continúa con la siguiente instrucción.
* **Valor predeterminado**: `"error"`

#### Ejemplo con argumentos generales

```json
{
    "type": "wait_for_element",
    "selector": {
        "type": "text",
        "value": "Cargar más elementos"
    },
    "timeout_s": 5,
    "wait_time_s": 2,
    "on_error": "skip"

}
```

### Instrucciones <a href="#click" id="click"></a>

#### `clic` <a href="#click" id="click"></a>

* **Descripción**: Hace clic en un elemento y espera una cantidad fija de segundos.
* **Args:**
  * `type: str = "click"`
  * `selector: dict`
    * `type: Enum["xpath", "css", "text"]`
    * `value: str`

**Ejemplo**:

```json
{
    "type": "click",
    "selector": {
        "type": "xpath",
        "value": "//button"
    }
}
```

#### `input` <a href="#input" id="input"></a>

* **Descripción**: Introduce texto en un elemento seleccionado.
* **Args:**
  * `type: str = "input"`
  * `selector: dict`
    * `type: Enum["xpath", "css", "text"]`
    * `value: str`
  * `value: str`&#x20;

**Ejemplo:**

```json
{
    "type": "input",
    "selector": {
        "type": "xpath",
        "value": "//input"
    },
    "value": "cajas para pizza"
}
```

#### `scroll` <a href="#scroll" id="scroll"></a>

* **Descripción**: Desplaza una cantidad fija de píxeles.
* **Args:**
  * `type: str = "scroll"`
  * `x: int`
  * `y: int`

**Ejemplo:**

```json
{
    "type": "scroll",
    "x": 0,
    "y": 100
}
```

#### `scroll_to_bottom` <a href="#scroll_to_bottom" id="scroll_to_bottom"></a>

* **Descripción**: Desplaza hasta el final durante una cantidad fija de segundos.
* **Args:**
  * `type: str = "scroll_to_bottom"`

**Ejemplo**:

```json
{
    "type": "scroll_to_bottom",
    "timeout_s": 10
}
```

#### `esperar` <a href="#wait" id="wait"></a>

* **Descripción**: Espera una cantidad fija de segundos.
* **Args:**
  * `type: str = "wait"`

**Ejemplo**:

```json
{
    "type": "wait",
    "wait_time_s": 2
}
```

#### `wait_for_element` <a href="#wait_for_element" id="wait_for_element"></a>

* **Descripción**: Espera a que el elemento cargue durante una cantidad fija de segundos.
* **Args:**
  * `type: str = "wait_for_element"`
  * `selector: dict`
    * `type: Enum["xpath", "css", "text"]`
    * `value: str`

**Ejemplo:**

```json
{
    "type": "wait_for_element",
    "selector": {
        "type": "text",
        "value": "Cargar más elementos"
    },
    "timeout_s": 5
}
```

#### `fetch_resource` <a href="#fetch_resource" id="fetch_resource"></a>

{% hint style="warning" %}
El `fetch_resource` la instrucción debe ser la instrucción final en la lista de instrucciones del navegador; cualquier instrucción posterior no se ejecutará.
{% endhint %}

* **Descripción**: Obtiene la primera ocurrencia de un recurso Fetch/XHR que coincida con el patrón establecido.
* **Args:**
  * `type: str = "fetch_resource"`
  * `filter: str(expresión RegEx)`
  * `on_error: Enum["error", "skip"]`

**Ejemplo:**

```json
{
    "type": "fetch_resource",
    "filter": "/graphql/item/"
}
```

### Validación de instrucciones

Cualquier inconsistencia con respecto al formato de la instrucción resultará en un `400` código de estado y un mensaje de error correspondiente.

Por ejemplo, una carga útil como esta:

```json
{
    "source": "universal",
    "url": "https://www.example.com/",
    "render": "html",
    "browser_instructions": [
        {
            "type": "unsupported-wait",
            "wait_time_s": 5
        }
    ]
}
```

Dará como resultado:

```json
{    
    "errors": {
        "message": "Unsupported action type `unsupported-wait`, choose from 'click,fetch_resource,input,scroll,scroll_to_bottom,wait,wait_for_element'"
    }
}
```

## Solución de problemas <a href="#status-codes" id="status-codes"></a>

### Códigos de estado <a href="#status-codes" id="status-codes"></a>

Consulta nuestros códigos de respuesta descritos [**aquí**](/products/es/web-scraper-api/response-codes.md). Los códigos de estado relacionados con la validación de instrucciones están documentados [**aquí**](/products/es/web-scraper-api/features/js-rendering-and-browser-control.md#instruction-validation).

### Errores y advertencias

Si hay un error o una advertencia resultante de sus acciones de navegación, la encontrará en el resultado bajo las claves `browser_instructions_error` o `browser_instructions_warnings`. Por ejemplo, si ha enviado las siguientes instrucciones del navegador y el `xpath` esperado no se encuentra en la página, el resultado incluirá una advertencia.

`browser_instructions`:

```json
[
    {
        "type": "input", 
        "selector": {
            "type": "xpath",
            "value": "//input[@type='search']"
        },
        "value": "oxylabs"
    }
]
```

Resultados:

```json
{
  "results": [
    {
      "content": "<!doctype html><html>
        Contenido después de ejecutar las instrucciones      
      </html>",
      "created_at": "2023-10-11 11:35:23",
      "updated_at": "2023-10-11 11:36:08",
      "browser_instructions_warnings": [
        {
          "action_type": "click",
          "msg": "No se pudo encontrar en la página el tipo de selector `xpath` con el valor `//input[@type=search]`."
        },
      ],
      "page": 1,
      "url": "https://example.com",
      "job_id": "7117835067442906113",
      "status_code": 200
    }
  ]
}

```

| Posibles errores y advertencias                                                                          |
| -------------------------------------------------------------------------------------------------------- |
| Se produjo un error inesperado al convertir las instrucciones del navegador en acciones.                 |
| Se produjo un error inesperado al ejecutar `{action.type}` instrucciones del navegador.                  |
| Acción `{action.type}` agotó el tiempo de espera.                                                        |
| No se pudo encontrar el tipo de selector `{selector.type}` con el valor `{selector.value}` en la página. |


---

# 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/js-rendering-and-browser-control.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.
