# Dicas para escrever expressões XPath

## A estrutura HTML pode diferir entre o documento raspado e o carregado no 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>

Ao escrever funções de seleção de elementos HTML, **certifique-se de trabalhar com documentos raspados em vez da versão ao vivo do site carregada no seu navegador**, pois os documentos podem diferir. O principal motivo por trás desse problema é a renderização de JavaScript. Quando um site é aberto, seu navegador é responsável por carregar documentos adicionais, como folhas de estilo CSS e scripts JavaScript, que podem alterar a estrutura do documento HTML inicial. Ao analisar HTMLs raspados, o Custom Parser não carrega o documento HTML da mesma forma que os navegadores (os analisadores ignoram instruções JavaScript), portanto a árvore HTML pode diferir entre o que o analisador e o navegador renderizam.

Como exemplo, veja o seguinte documento HTML:

```html
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div>
        <h3>This is a product</h3>
        <div id="price-container">
            <p>This is the price:</p>
        </div>
        <p>And here is some description</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>
```

Se você abrir o documento via navegador, ele mostrará o preço que você pode selecionar usando a seguinte expressão XPath `//p[@id="price"]`:

<figure><img src="https://1214208351-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FzrXw45naRpCZ0Ku9AjY1%2Fuploads%2Fa1Q7Xy0RGkCtyypmJiaz%2Fimage.png?alt=media&#x26;token=b8a517cb-77a5-49c3-9611-d61923657e83" alt=""><figcaption></figcaption></figure>

Agora, se você desabilitar a renderização de JavaScript no navegador, o site será renderizado da seguinte forma:

<figure><img src="https://1214208351-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FzrXw45naRpCZ0Ku9AjY1%2Fuploads%2FAZ0eGq3gY8dklt1AayeD%2Fimage.png?alt=media&#x26;token=0d2254da-65f9-4fde-8f0b-68ab5caddc4b" alt=""><figcaption></figcaption></figure>

A mesma `//p[@id="price"]` A expressão XPath não corresponde mais ao preço, pois ele não é renderizado.

## Certifique-se de escrever todos os seletores HTML possíveis para o elemento de destino <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 vários motivos, a mesma página raspada duas vezes pode ter layouts diferentes (User-Agents diferentes usados na raspagem, site de destino fazendo testes A/B, etc.).

Para lidar com esse problema, sugerimos definir `parsing_instructions` para o documento inicialmente raspado e testar essas instruções imediatamente com vários outros resultados de tarefas raspadas do mesmo tipo de página.

Funções de seletor HTML (`xpath`/`xpath_one`) oferecem suporte a [**recursos de fallback de seletor**](https://developers.oxylabs.io/documentation/pt-br/solucoes-de-scraping/web-scraper-api/features/custom-parser/list-of-functions/function-examples#xpath).

## Fluxo sugerido para escrever seletores HTML <a href="#suggested-html-selector-writing-flow" id="suggested-html-selector-writing-flow"></a>

1. Raspe o documento HTML da página de destino usando a Scraper API.
2. Desative o JavaScript e abra o HTML raspado localmente no seu navegador. Se o JavaScript for desativado **depois que** o HTML for aberto, certifique-se de recarregar a página para que o HTML possa recarregar sem JavaScript.
3. [**Use as ferramentas de desenvolvedor do navegador**](https://www.computerhope.com/issues/ch002153.htm).

<figure><img src="https://1214208351-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FzrXw45naRpCZ0Ku9AjY1%2Fuploads%2FoG0t7V4hrgrtY5EgtqvF%2Fimage.png?alt=media&#x26;token=c53e0220-0cef-420f-974b-7123c49c1187" alt=""><figcaption></figcaption></figure>

### Como escrever instruções de parsing  <a href="#how-to-write-parsing-instructions-inlineextension" id="how-to-write-parsing-instructions-inlineextension"></a>

Digamos que você tenha a seguinte página para analisar:

```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">This is a cool product</h1>
    <div id="description-container">
        <h2>This is a product description</h2>
        <ul>
            <li class="description-item">Durable</li>
            <li class="description-item">Nice</li>
            <li class="description-item">Sweet</li>
            <li class="description-item">Spicy</li>
        </ul>
    </div>
    <div id="price-container">
        <h2>Variants</h2>
        <div id="variants">
            <div class="variant">
                <p class="color">Red</p>
                <p class="price">99.99</p>
            </div>
            <div class="variant">
                <p class="color">Green</p>
                <p class="price">87.99</p>
            </div>
            <div class="variant">
                <p class="color">Blue</p>
                <p class="price">65.99</p>
            </div>
            <div class="variant">
                <p class="color">Black</p>
                <p class="price">99.99</p>
            </div>
        </div>
    </div>
</div>
</body>
</html>
```

<figure><img src="https://1214208351-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FzrXw45naRpCZ0Ku9AjY1%2Fuploads%2FHJ39wJ8MBPxXnS8pjXuF%2Fimage.png?alt=media&#x26;token=ac49bb0c-655e-4bc5-abb2-7b82d7b56a6a" alt=""><figcaption></figcaption></figure>

### Analisar título do produto

Crie um novo objeto JSON e atribua um novo campo a ele.

Você pode nomear o campo como preferir com algumas exceções (o nome de campo definido pelo usuário não pode começar com um sublinhado `_` , por exemplo, `"_title"`).&#x20;

O nome do campo será exibido no resultado analisado.

O novo campo deve conter um valor do tipo objeto JSON:

```json
{
    "title": {}  // definindo um campo de título a ser analisado
} 
```

Se você fornecer essas instruções ao Custom Parser, ele não fará nada ou enviará uma reclamação de que você não forneceu nenhuma instrução.

Para realmente analisar o título no `título` campo, você deve definir um pipeline de processamento de dados dentro do objeto `título` usando a propriedade reservada `_fns` (que é sempre do tipo array):

```json
{
    "title": {
        "_fns": []  // definindo o pipeline de processamento de dados para o campo title
    }
}
```

Para que o Custom Parser selecione o texto do título, você pode utilizar a função de seletor HTML `xpath_one`. Para usar a função no documento HTML, ela deve ser adicionada ao pipeline de processamento de dados. A função é definida como um objeto JSON com `_fn` (nome da função) e `_args` (argumentos da função) obrigatórios. Veja a lista completa de definições de funções [**aqui**](https://developers.oxylabs.io/documentation/pt-br/solucoes-de-scraping/web-scraper-api/features/custom-parser/writing-instructions-manually/list-of-functions).

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

As instruções de parsing acima devem produzir o seguinte resultado:

```json
{
    "title": "This is a cool product"
}
```

### Analisar descrição

Da mesma forma, nas instruções de parsing, você pode definir outro campo onde o contêiner da descrição do produto, o título da descrição e os itens serão analisados. Para que o título e os itens da descrição fiquem aninhados sob o `descrição` objeto, a estrutura das instruções deve ser a seguinte:

```json
{
    "title": {...},
    "description": { // contêiner da descrição
        "title": {}, // título da descrição
        "items": {} // itens da descrição
    } 
}
```

A estrutura fornecida das instruções de parsing implica que `description.title` e `description.items` serão analisados com base no `descrição` elemento. Você pode definir um pipeline para o campo `descrição` Neste caso, isso é feito primeiro, pois simplificará a expressão XPath do título da descrição.

```json
{
    "title": {...},
    "description": {
        "_fns": [
            {
                "_fn": "xpath_one",
                "_args": ["//div[@id='description-container']"]
            }
        ],  // O resultado do pipeline será usado ao analisar `title` e `items`.
        "title": {},
        "items": {}
    }
}
```

No exemplo, o pipeline `description._fns` selecionará o elemento HTML `description-container` , que será usado como ponto de referência para analisar o título e os itens da descrição.

Para analisar os campos restantes da descrição, adicione dois pipelines diferentes para os campos `description.items`, e `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()"
                    ]
                }
            ]
        }
    }
}
```

Observe como a função `xpath` é usada em vez de `xpath_one` para extrair todos os itens que correspondem à expressão XPath.

As instruções de parsing produzem o seguinte resultado:

```json
{
    "title": {...},
    "description": {
        "title": "This is description about the product",
        "items": [
            "Durable",
            "Nice",
            "Sweet",
            "Spicy"
        ]
    }
}
```

### Analisar variantes do produto

O exemplo a seguir mostra a estrutura das instruções se você quiser analisar informações no campo `product_variants` , que conterá uma lista de objetos de variante. Neste caso, o objeto variante possui campos `preço` e `color` e price.

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

Comece selecionando todos os elementos de variantes do produto:

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

Para fazer do `product_variants` uma lista contendo objetos JSON, você terá que iterar pelas variantes encontradas usando `_items` iterator:

```json
{
    "title": {...},
    "description": {...},
    "product_variants": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": ["//div[@class='variant']"]
            }
        ],
        "_items": { // com isso, você está instruindo a processar os elementos encontrados um por um
            // instruções de campo a serem descritas aqui
        } 
    }
}
```

Por fim, defina instruções sobre como analisar os campos `color` e `preço` :

```json
{
    "title": {...},
    "description": {...},
    "product_variants": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": [
                    "//div[@class='variant']"
                ]
            }
        ],
        "_items": {
            "color": {
                "_fns": [
                    {
                        "_fn": "xpath_one",
                        "_args": [
                            // Como estamos usando expressões XPath relativas,
                            // certifique-se de que o XPath comece com um ponto (.)
                            ".//p[@class='color']/text()"
                        ]
                    }
                ]
            },
            "price": {
                "_fns": [
                    {
                        "_fn": "xpath_one",
                        "_args": [
                            ".//p[@class='price']/text()"
                        ]
                    }
                ]
            }
        }
    }
}
```

Com `product_variants` descrito, as instruções finais ficarão da seguinte forma:

```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()"
                        ]
                    }
                ]
            }
        }
    }
}
```

O que produzirá a seguinte saída:

```json
{
    "title": "This is a cool product",
    "description": {
        "title": "This is a product description",
        "items": [
            "Durable",
            "Nice",
            "Sweet",
            "Spicy"
        ]
    },
    "product_variants": [
        {
            "color": "Red",
            "price": "99.99"
        },
        {
            "color": "Green",
            "price": "87.99"
        },
        {
            "color": "Blue",
            "price": "65.99"
        },
        {
            "color": "Black",
            "price": "99.99"
        }
    ]
}
```

Você pode encontrar mais exemplos de instruções de parsing aqui: [**Exemplos de instruções de parsing**](https://developers.oxylabs.io/documentation/pt-br/solucoes-de-scraping/web-scraper-api/features/custom-parser/writing-instructions-manually/parsing-instruction-examples).
