# 解析指令示例

以下 HTML 片段使用后续章节中的示例解析指令进行解析。

### 示例 HTML <a href="#sample-html" id="sample-html"></a>

```html
<body>
    <div id="products">
        <div class="product" id="shoes">
            <div class="title">鞋子</div>
            <div class="price">223.12</div>
            <div class="description">
                <ul>
                    <li class="description-item">超级</li>
                </ul>
            </div>
        </div>
        <div class="product" id="pants">
            <div class="title">裤子</div>
            <div class="price">60.12</div>
            <div class="description">
                <ul>
                    <li class="description-item">惊人</li>
                    <li class="description-item">品质</li>
                </ul>
            </div>
        </div>
        <div class="product" id="socks">
            <div class="title">袜子</div>
            <div class="price">123.12</div>
            <div class="description">
                <ul>
                    <li class="description-item">非常</li>
                    <li class="description-item">不错</li>
                    <li class="description-item">袜子</li>
                </ul>
            </div>
        </div>
    </div>
</body>
```

### 最低限度 <a href="#bare-minimum" id="bare-minimum"></a>

{% hint style="info" %}
使用场景：你想提取所有内容中的文本 **鞋子** **描述** **项**.
{% endhint %}

*示例 1. 使用 XPath 选择鞋子描述项。*

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

该 `xpath` 函数将找到单个项，并将其作为字符串放入列表中：

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

精确的 `xpath` 函数行为如下所述 [**这里**](/products/cn/web-scraper-api/features/custom-parser/writing-instructions-manually/list-of-functions.md).

### 嵌套解析指令 <a href="#nested-parsing-instructions" id="nested-parsing-instructions"></a>

{% hint style="info" %}
使用场景：你想解析与鞋子相关的所有信息。此外，解析结果还应体现所提供 HTML 的文档结构。
{% endhint %}

你要定位的是示例 HTML 的这部分：

```html
<div class="product" id="shoes">
    <div class="title">鞋子</div>
    <div class="price">223.12</div>
    <div class="description">
        <ul>
            <li class="description-item">超级</li>
        </ul>
    </div>
</div>
```

并且你希望解析结果具有如下结构：

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

解析指令如下所示。

*示例 2. 使用解析指令来解析* `鞋子` *信息。*

```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` 的工作方式与 `xpath`类似，但它不是返回所有匹配项的列表，而是 **返回第一个匹配项**.

在上面的示例中， `鞋子` 属性是最外层指令作用域中唯一定义的属性。 `鞋子` 属性包含嵌套解析指令。

该 `鞋子` 指令作用域没有定义管道（`_fns` 属性缺失）。这意味着在 `title`, `price`，以及 `描述` 作用域中定义的管道将把待解析文档作为管道输入。

在示例 2 中，你可以看到 `//div[@id='shoes']` 在 XPath 表达式中的重复。通过在 `鞋子` 作用域中定义管道，可以避免这种重复：

*示例 3. 在* `鞋子` *作用域指令中定义管道以避免 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()"]
                }
            ]
        }
    }
}
```

使用示例 3 中提供的解析指令， 自定义解析器 将：

1. 从处理 `shoes._fns` 管道开始，该管道将输出 `鞋子` HTML 元素；
2. 取 `shoes._fns` 管道输出，并将其作为定义在 `title`, `price`，以及 `描述` 作用域中的管道的输入；
3. 处理 `title`, `price`，以及 `描述` 管道以生成最终值。

结果将与示例 2 的结果相同：

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

示例 2 和示例 3 的主要区别在于，在示例 3 中，管道定义在 `鞋子` 作用域中。 **这个额外的管道会选择鞋子对应的元素，并将其传递给在指令层级更深处找到的后续管道。**

### 嵌套对象列表 <a href="#list-of-nested-objects" id="list-of-nested-objects"></a>

{% hint style="info" %}
**使用场景：** 之前，你只想解析 `鞋子` 信息。现在你想解析 HTML 中所有商品的信息。
{% endhint %}

该 [**示例 HTML**](/products/cn/web-scraper-api/features/custom-parser/writing-instructions-manually/parsing-instruction-examples.md#sample-html) 再次用作待解析文档。

如果你希望解析结果看起来像这样：

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

解析指令如下：

*示例 4. 解析 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()"]
                    }
                ]
            }
        }
    }
}
```

解析指令结构看起来与示例 3 中的类似。不过，有两个主要例外：

1. `xpath` 用来代替 `xpath_one` 中的 `products._fns` 管道。 `products._fns` 现在，管道会输出与所提供 XPath 表达式匹配的所有元素的列表（商品元素列表）。
2. `_items` 保留属性用于表示你希望通过遍历 `products._fns` 管道输出并 **分别传递/处理每个列表项** 到下层指令作用域中来构建一个列表。

如果 `_items` 保留属性没有在示例 4 的解析指令中使用，解析结果将如下所示：

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

{% hint style="warning" %}
`_items` 用于指定自定义解析器必须传递 ***单独的列表项*** 而不是 ***整个列表*** 到解析指令中。
{% endhint %}

### 从列表中选择第 N 个元素  <a href="#select-n-th-element-from-a-list" id="select-n-th-element-from-a-list"></a>

本节展示了管道的灵活性。同一个问题可以用不同方式处理。

可以使用多种方式从任意值的列表中选择第 N 个元素。

{% hint style="info" %}
**使用场景：** 你想选择页面上的第二个商品价格。
{% endhint %}

该 [**示例 HTML**](#sample-html) 再次作为示例使用。你有多种选项可以选择第 2 个商品。

#### 选项 1 <a href="#option-1" id="option-1"></a>

你可以利用 XPath `[]` 选择器，并在 XPath 表达式中定义选择。

*示例 5. 使用 XPath \[] 选择器选择第 2 个价格。*

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

结果：

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

#### 选项 2 <a href="#option-2" id="option-2"></a>

你也可以使用 `xpath` 函数查找所有价格，并将其传递给 `select_nth`函数，它会从提取出的价格列表中选择第 N 个元素。

*示例 6. 使用 \`select\_nth\` 函数选择第 2 个值。*

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

结果：

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

{% hint style="warning" %}
注意， `select_nth` 函数会从列表中返回一个项，而 `xpath` 函数会返回一个项列表，即使只找到一个项也是如此。
{% endhint %}

#### 选项 3  <a href="#option-3" id="option-3"></a>

你可以将 `select_nth` 用于任何列表类型，包括 HTML 元素列表：

*示例 7. 使用* `class="product"` *==> 从列表中选择第 2 个商品元素 ==> 从所选商品 HTML 元素中提取价格文本*.

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

结果：

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

### 错误处理 <a href="#error-handling" id="error-handling"></a>

当给定以下 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>
```

并尝试使用以下解析指令解析它时：

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

自定义解析器 将返回一个解析结果，其中 `price` 和 `title` 被正常解析，但 `描述` 由于 `convert_to_float` 函数无法转换而解析失败 `string` 到 `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"
        }
    ]
}
```

默认情况下，所有错误都会被计为警告，并放置在 `_warnings` 列表中。如果你想在解析字段时忽略错误，可以使用 `"_on_error": "suppress"` 参数来抑制警告/错误：

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

这将生成以下结果：

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

### 数组的数组 <a href="#array-of-arrays" id="array-of-arrays"></a>

自定义解析器 允许在解析结果中使用 N 维数组。例如，我们来使用以下 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>
```

假设你想解析文档，使结果成为一个 3x3 的二维整数数组：

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

要将 HTML 解析为上面的 JSON，你可以使用以下解析指令：

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


---

# 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/cn/web-scraper-api/features/custom-parser/writing-instructions-manually/parsing-instruction-examples.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.
