# Exemplos de instruções de parsing

O seguinte trecho HTML é analisado usando instruções de parsing de exemplo nas próximas seções.

### HTML de exemplo <a href="#sample-html" id="sample-html"></a>

```html
<body>
    <div id="products">
        <div class="product" id="shoes">
            <div class="title">Shoes</div>
            <div class="price">223.12</div>
            <div class="description">
                <ul>
                    <li class="description-item">Super</li>
                </ul>
            </div>
        </div>
        <div class="product" id="pants">
            <div class="title">Pants</div>
            <div class="price">60.12</div>
            <div class="description">
                <ul>
                    <li class="description-item">Amazing</li>
                    <li class="description-item">Quality</li>
                </ul>
            </div>
        </div>
        <div class="product" id="socks">
            <div class="title">Socks</div>
            <div class="price">123.12</div>
            <div class="description">
                <ul>
                    <li class="description-item">Very</li>
                    <li class="description-item">Nice</li>
                    <li class="description-item">Socks</li>
                </ul>
            </div>
        </div>
    </div>
</body>
```

### Mínimo necessário <a href="#bare-minimum" id="bare-minimum"></a>

{% hint style="info" %}
Caso de uso: você quer extrair o texto de todos os **shoes** **description** **itens**.
{% endhint %}

*Exemplo 1. Seleção dos itens de descrição de shoes usando XPath.*

```json
{
    "shoes_description": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": [
                    ".//div[@id='shoes']//li[@class='description-item']/text()"
                ]
            }
        ]
    }
}
```

O `xpath` a função encontrará um único item e o colocará em uma lista como uma string:

```json
{
    "shoes_description": [
        "Super"
    ]
}
```

O exato `xpath` comportamento da função é descrito [**aqui**](https://developers.oxylabs.io/documentation/pt-br/solucoes-de-scraping/web-scraper-api/features/custom-parser/writing-instructions-manually/list-of-functions).

### Instruções de parsing aninhadas <a href="#nested-parsing-instructions" id="nested-parsing-instructions"></a>

{% hint style="info" %}
Caso de uso: você quer analisar todas as informações relacionadas a shoes. Além disso, o resultado analisado deve representar a estrutura do documento do HTML fornecido.
{% endhint %}

Você está mirando esta parte do HTML de exemplo:

```html
<div class="product" id="shoes">
    <div class="title">Shoes</div>
    <div class="price">223.12</div>
    <div class="description">
        <ul>
            <li class="description-item">Super</li>
        </ul>
    </div>
</div>
```

E você gostaria que o resultado analisado tivesse a seguinte estrutura:

```json
{
    "shoes": {
        "title": "Shoes",
        "price": "223.12",
        "description": [
            "Super"
        ]
    }
}
```

As instruções de parsing ficariam assim.

*Exemplo 2. Instruções de parsing são usadas para analisar* `shoes` *informações.*

```json
{
    "shoes": {
        "title": {
            "_fns": [
                {
                    "_fn": "xpath_one",
                    "_args": ["//div[@id='shoes']/div[@class='title']/text()"]
                }
            ]
        },
        "price": {
            "_fns": [
                {
                    "_fn": "xpath_one",
                    "_args": ["//div[@id='shoes']/div[@class='price']/text()"]
                }
            ]
        },
        "description": {
            "_fns": [
                {
                    "_fn": "xpath",
                    "_args": ["//div[@id='shoes']//li[@class='description-item']/text()"]
                }
            ]
        }
    }
}
```

`xpath_one` funciona de forma semelhante a `xpath`, mas ao invés de retornar uma lista de todas as correspondências, ela **retorna o primeiro item correspondente**.

No exemplo acima, a `shoes` propriedade é a única propriedade definida no escopo de instruções mais externo. A `shoes` propriedade contém instruções de parsing aninhadas.

O `shoes` o escopo de instruções não tem um pipeline definido (`_fns` a propriedade está ausente). Isso significa que pipelines definidos em `title`, `price`, e `description` escopos usarão o documento sob análise como entrada do pipeline.

No Exemplo 2, você pode ver uma repetição de `//div[@id='shoes']` em expressões XPath. A repetição pode ser evitada definindo um pipeline no `shoes` escopo:

*Exemplo 3. Definindo um pipeline no* `shoes` *escopo de instruções para evitar repetição de expressões XPath.*

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

Usando as instruções de parsing fornecidas no Exemplo 3, o Custom Parser irá:

1. Começar processando `shoes._fns` pipeline, que produzirá o `shoes` elemento HTML;
2. Pegar a saída do `shoes._fns` pipeline e usá-la como entrada para pipelines definidos em `title`, `price`, e `description` escopos;
3. Processar `title`, `price`, e `description` pipelines para produzir os valores finais.

O resultado será igual ao resultado do Exemplo 2:

```json
{
    "shoes": {
        "title": "Shoes",
        "price": "223.12",
        "description": [
            "Super"
        ]
    }
}
```

A principal diferença entre o Exemplo 2 e o Exemplo 3 é que, no Exemplo 3, o pipeline é definido no `shoes` escopo. **Esse pipeline adicional seleciona o elemento dos shoes e o passa para pipelines mais adiante encontrados na hierarquia de instruções.**

### Lista de objetos aninhados <a href="#list-of-nested-objects" id="list-of-nested-objects"></a>

{% hint style="info" %}
**Caso de uso:** Anteriormente, você queria analisar apenas `shoes` informações. Agora você quer analisar as informações de todos os produtos no HTML.
{% endhint %}

O [**HTML de exemplo**](#sample-html) é usado novamente como o documento sob análise.

Se você quiser que seu resultado analisado fique assim:

```json
{
    "products": [
        {
            "title": "Shoes",
            "price": "223.12",
            "description": [
                "Super"
            ]
        },
        {
            "title": "Pants",
            "price": "60.12",
            "description": [
                "Amazing",
                "Quality"
            ]
        },
        {
            "title": "Socks",
            "price": "123.12",
            "description": [
                "Very",
                "Nice",
                "Socks"
            ]
        }
    ]
}
```

As instruções de parsing ficariam assim:

*Exemplo 4. Analisando todos os produtos encontrados no documento HTML.*

```json
{
    "products": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": ["//div[@class='product']"]
            }
        ],
        "_items": {
            "title": {
                "_fns": [
                    {
                        "_fn": "xpath_one",
                        "_args": ["./div[@class='title']/text()"]
                    }
                ]
            },
            "price": {
                "_fns": [
                    {
                        "_fn": "xpath_one",
                        "_args": ["./div[@class='price']/text()"]
                    }
                ]
            },
            "description": {
                "_fns": [
                    {
                        "_fn": "xpath",
                        "_args": [".//li[@class='description-item']/text()"]
                    }
                ]
            }
        }
    }
}
```

A estrutura das instruções de parsing é semelhante à do Exemplo 3. Entretanto, há duas grandes exceções:

1. `xpath` é usado em vez de `xpath_one` em `products._fns` pipeline. `products._fns` o pipeline agora produzirá uma lista de todos os elementos que corresponderem à expressão XPath fornecida (uma lista de elementos product).
2. `_items` a propriedade reservada é usada para indicar que você quer formar uma lista iterando por cada item da `products._fns` saída do pipeline e **passando/processando cada item da lista separadamente** pelo escopo do pipeline.

Se a `_items` propriedade reservada não fosse usada nas instruções de parsing do Exemplo 4, o resultado analisado seria o seguinte:

```json
{
    "products": {
        "title": [
            "Shoes",
            "Pants",
            "Socks"
        ],
        "price": [
            "223.12",
            "60.12",
            "123.12"
        ],
        "description": [
            [
                "Super"
            ],
            [
                "Amazing",
                "Quality"
            ],
            [
                "Very",
                "Nice",
                "Socks"
            ]
        ]
    }
}
```

{% hint style="warning" %}
`_items` é usado para especificar que o Custom Parser deve passar ***itens separados da lista*** em vez da ***lista inteira*** pelas instruções de parsing.
{% endhint %}

### Selecionar o N-ésimo elemento de uma lista  <a href="#select-n-th-element-from-a-list" id="select-n-th-element-from-a-list"></a>

Esta seção demonstra a flexibilidade dos pipelines. O mesmo problema pode ser abordado de diferentes formas.

Várias opções podem ser usadas para selecionar o N-ésimo elemento de uma lista de quaisquer valores.

{% hint style="info" %}
**Caso de uso:** você quer selecionar o preço do segundo produto da página.
{% endhint %}

O [**HTML de exemplo**](#sample-html) é novamente usado como exemplo. Você tem múltiplas opções para selecionar o 2º produto.

#### Opção 1 <a href="#option-1" id="option-1"></a>

Você pode utilizar o seletor XPath `[]` e definir a seleção na expressão XPath.

*Exemplo 5. Selecionar o 2º preço usando o seletor XPath \[].*

```json
{
    "second_price": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": [
                    "(//div[@class='price'])[2]/text()"
                ]
            }
        ]
    }
}
```

Resultado:

```json
{
    "second_price": [
        "60.12"
    ]
}
```

#### Opção 2 <a href="#option-2" id="option-2"></a>

Você também pode usar a `xpath` função para encontrar todos os preços e encadeá-la para a função `select_nth`, que seleciona o n-ésimo elemento da lista extraída de preços.

*Exemplo 6. Selecionar o 2º valor usando a função \`select\_nth\`.*

```json
{
    "second_price": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": [
                    "//div[@class='price']/text()"
                ]
            },
            {
                "_fn": "select_nth",
                "_args": 1
            }
        ]
    }
}
```

Resultado:

```json
{
    "second_price": "60.12"
}
```

{% hint style="warning" %}
Observe como a `select_nth` função retorna um item de uma lista enquanto a `xpath` função retorna uma lista de itens, mesmo se um único item for encontrado.
{% endhint %}

#### Opção 3  <a href="#option-3" id="option-3"></a>

Você pode usar `select_nth` com qualquer tipo de lista, incluindo listas de elementos HTML:

*Exemplo 7. Selecionando todos os elementos HTML de produto com* `class="product"` *==> selecionando o 2º elemento de produto da lista ==> extraindo o texto do preço do elemento HTML do produto selecionado*.

```json
{
    "second_price": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": ["//div[@class='product']"]
            },
            {
                "_fn": "select_nth",
                "_args": 1
            },
            {
                "_fn": "xpath",
                "_args": ["./div[@class='price']/text()"]
            }
        ]
    }
}
```

Resultado:

```json
{
    "second_price": ["60.12"]
}
```

### Tratamento de erros <a href="#error-handling" id="error-handling"></a>

Dado o seguinte trecho HTML:

```html
<div class="product" id="shoes">
    <div class="title">Nice Shoes</div>
    <div class="price">223.12</div>
    <div class="description">Super</div>
</div>
```

E tentando analisá-lo com as seguintes instruções de parsing:

```json
{
    "product": {
        "_fns": [
            {
                "_fn": "xpath_one",
                "_args": ["//div[@id='shoes']"]
            }
        ],
        "price": {
            "_fns": [
                {
                    "_fn": "xpath_one",
                    "_args": ["//div[@class='price']/text()"]
                }
            ]
        },
        "title": {
            "_fns": [
                {
                    "_fn": "xpath_one",
                    "_args": ["//div[@class='title']/text()"]
                }
            ]
        },
        "description": {
            "_fns": [
                {
                    "_fn": "xpath_one",
                    "_args": ["//div[@class='description']/text()"]
                },
                {
                    "_fn": "convert_to_float"
                }
            ]
        }
    }
}
```

O Custom Parser retornará um resultado analisado onde `price` e `title` foram analisados normalmente, mas o `description` falhou ao ser analisado devido à `convert_to_float` função falhando ao converter `string` to `float`:

```json
{
    "product": {
        "price": "223.12",
        "title": "Shoes",
        "description": null
    },
    "_warnings": [
        {
            "_fn": "convert_to_float",
            "_fn_idx": 1,
            "_msg": "Failed to process function.",
            "_path": ".product.description"
        }
    ]
}
```

Por padrão, todos os erros são contados como avisos e são colocados dentro de `_warnings` a lista. Se você quiser ignorar os erros ao analisar um campo, eles podem suprimir avisos/erros com `"_on_error": "suppress"` parâmetro:

```json
{
    "product": {
        ...,
        "description": {
            "_on_error": "suppress",
            "_fns": [
                {
                    "_fn": "xpath_one",
                    "_args": ["//div[@class='description']/text()"]
                },
                {
                    "_fn": "convert_to_float"
                }
            ]
        }
    }
}
```

O que então produzirá o seguinte resultado:

```json
{
    "product": {
        "price": "223.12",
        "title": "Shoes",
        "description": null
    }
}
```

### Array de arrays <a href="#array-of-arrays" id="array-of-arrays"></a>

O Custom Parser permite arrays N-dimensionais em resultados analisados. Como exemplo, vamos usar o seguinte trecho HTML:

```html
<div class="row">
    <div class="column">1</div>
    <div class="column">2</div>
    <div class="column">3</div>
</div>
<div class="row">
    <div class="column">4</div>
    <div class="column">5</div>
    <div class="column">6</div>
</div>
<div class="row">
    <div class="column">7</div>
    <div class="column">8</div>
    <div class="column">9</div>
</div>
```

Suponha que você queira analisar o documento de modo que o resultado seja um array 2D 3x3 de inteiros:

```json
{
    "table": [
        [1, 2, 3],
        [4, 5, 6],
        [7, 8, 9],
    ]
}
```

Para converter o HTML no JSON acima, você pode usar as seguintes instruções de parsing:

```json
{
    "table": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": ["//div[@class='row']"]
            },
            {
                "_fn": "xpath",
                "_args": [".//div[@class='column']/text()"]
            },
            {
                "_fn": "convert_to_int"
            }
        ]
    }
}
```
