> For the complete documentation index, see [llms.txt](https://developers.oxylabs.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developers.oxylabs.io/products/cn/web-scraper-api/features/custom-parser/writing-instructions-manually/tips-for-writing-xpath-expressions.md).

# 编写 XPath 表达式的提示

## 抓取的文档与浏览器加载的文档之间的 HTML 结构可能不同 <a href="#html-structure-may-differ-between-scraped-and-browser-loaded-document" id="html-structure-may-differ-between-scraped-and-browser-loaded-document"></a>

在编写 HTML 元素选择函数时， **请确保使用抓取的文档，而不是浏览器中加载的实时网站版本**，因为文档可能不同。此问题背后的主要原因是 JavaScript 渲染。当网站被打开时，浏览器负责加载额外的文档，例如 CSS 样式表和 JavaScript 脚本，这些内容可能会改变初始 HTML 文档的结构。在解析抓取的 HTML 时，自定义解析器不会像浏览器那样加载 HTML 文档（解析器会忽略 JavaScript 指令），因此解析器和浏览器渲染出的 HTML 树可能不同。

例如，请看下面的 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>
```

如果你通过浏览器打开该文档，它将显示价格，你可以使用以下 XPath 表达式选择它 `//p[@id="price"]`:

<figure><img src="/files/4263a80fbbd4ef6f3fee91b1294e93b793d8cbe6" alt=""><figcaption></figcaption></figure>

现在，如果你在浏览器中禁用 JavaScript 渲染，网站将如下所示：

<figure><img src="/files/5453d5f53fc12f8b4f0b8a90eeaee18e5409a25c" alt=""><figcaption></figcaption></figure>

相同的 `//p[@id="price"]` XPath 表达式将不再匹配价格，因为它未被渲染。

## 请确保为目标元素编写所有可能的 HTML 选择器 <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>

由于各种原因，同一个页面抓取两次后可能会有不同的布局（抓取时使用了不同的 User Agents、目标网站在进行 A/B 测试等）。

为了解决这个问题，我们建议定义 `parsing_instructions` 用于初始抓取文档的内容，并立即使用同一页面类型的多个其他抓取任务结果来测试这些指令。

HTML 选择器函数（`xpath`/`xpath_one`）支持 [**选择器回退**](/products/cn/web-scraper-api/features/custom-parser/writing-instructions-manually/list-of-functions/function-examples.md#xpath).

## 建议的 HTML 选择器编写流程 <a href="#suggested-html-selector-writing-flow" id="suggested-html-selector-writing-flow"></a>

1. 使用 网页爬虫API 抓取目标页面的 HTML 文档。
2. 禁用 JavaScript，并在浏览器中本地打开抓取的 HTML。如果 JavaScript 是在 **之后** HTML 被打开后才禁用的，请确保重新加载页面，以便 HTML 能在没有 JavaScript 的情况下重新加载。
3. [**使用浏览器开发者工具**](https://www.computerhope.com/issues/ch002153.htm).

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

### 如何编写解析指令  <a href="#how-to-write-parsing-instructions-inlineextension" id="how-to-write-parsing-instructions-inlineextension"></a>

假设你有以下页面需要解析：

```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="/files/8381407529fe093572c59b4ccaf82cc6f6ed7763" alt=""><figcaption></figcaption></figure>

### 解析产品标题

创建一个新的 JSON 对象，并为其分配一个新字段。

你可以按自己的喜好命名该字段，但有一些例外（用户定义的字段名不能以下划线开头 `_` ，例如 `"_title"`).&#x20;

字段名称将显示在解析结果中。

该新字段必须保存一个 JSON 对象类型的值：

```json
{
    "title": {}  // defining a title field to be parsed
} 
```

如果你将这些指令提供给自定义解析器，它将不会执行任何操作，或者会提示你尚未提供任何指令。

要实际将标题解析到 `title` 字段中，你必须在 `title` 对象内部使用保留的 `_fns` 属性（它始终是数组类型）定义一个数据处理管道：

```json
{
    "title": {
        "_fns": []  // defining data processing pipeline for the title field
    }
}
```

为了让自定义解析器选择标题文本，你可以使用 HTML 选择器函数 `xpath_one`。要在 HTML 文档上使用该函数，应将其添加到数据处理管道中。该函数被定义为一个 JSON 对象，包含必需的 `_fn` （函数名）以及必需的 `_args` （函数参数）字段。请查看函数定义的完整列表 [**此处**](/products/cn/web-scraper-api/features/custom-parser/writing-instructions-manually/list-of-functions.md).

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

上述解析指令应产生以下结果：

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

### 解析描述

类似地，在解析指令中，你可以定义另一个字段，用于解析产品描述容器、描述标题和条目。为了让描述的标题和条目嵌套在 `description` 对象下，指令结构应如下所示：

```json
{
    "title": {...},
    "description": { // description container
        "title": {}, // description title
        "items": {} // description items
    } 
}
```

给定的解析指令结构意味着 `description.title` 和 `description.items` 将基于 `description` 元素进行解析。你可以为 `description` 字段定义一个管道。在这种情况下，先这样做会简化描述标题的 XPath 表达式。

```json
{
    "title": {...},
    "description": {
        "_fns": [
            {
                "_fn": "xpath_one",
                "_args": ["//div[@id='description-container']"]
            }
        ],  // Pipeline result will be used when parsing `title` and `items`.
        "title": {},
        "items": {}
    }
}
```

在该示例中， `description._fns` 管道将选择 `description-container` HTML 元素，该元素将用作解析描述标题和条目的参考点。

要解析其余描述字段，请为这些字段添加两个不同的管道 `description.items`、 `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()"
                    ]
                }
            ]
        }
    }
}
```

请注意， `xpath` 函数用于替代 `xpath_one` ，以提取所有匹配该 XPath 表达式的条目。

解析指令会产生以下结果：

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

### 解析产品变体

下面的示例展示了如果你想将信息解析到 `product_variants` 字段中的指令结构，该字段将包含一个变体对象列表。在这种情况下，变体对象有 `price` 和 `color` 字段。

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

首先选择所有产品变体元素：

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

为了使 `product_variants` 成为一个包含 JSON 对象的列表，你需要使用 `_items` 迭代器遍历找到的变体：

```json
{
    "title": {...},
    "description": {...},
    "product_variants": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": ["//div[@class='variant']"]
            }
        ],
        "_items": { // with this, you are instructing to process found elements one by one
            // field instructions to be described here
        } 
    }
}
```

最后，定义如何解析 `color` 和 `price` 字段的指令：

```json
{
    "title": {...},
    "description": {...},
    "product_variants": {
        "_fns": [
            {
                "_fn": "xpath",
                "_args": [
                    "//div[@class='variant']"
                ]
            }
        ],
        "_items": {
            "color": {
                "_fns": [
                    {
                        "_fn": "xpath_one",
                        "_args": [
                            // As we are using relative XPath expressions,
                            // make sure XPath starts with a dot (.)
                            ".//p[@class='color']/text()"
                        ]
                    }
                ]
            },
            "price": {
                "_fns": [
                    {
                        "_fn": "xpath_one",
                        "_args": [
                            ".//p[@class='price']/text()"
                        ]
                    }
                ]
            }
        }
    }
}
```

使用 `product_variants` 如上所述，最终指令将如下所示：

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

这将产生以下输出：

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

你可以在这里找到更多解析指令示例： [**解析指令示例**](/products/cn/web-scraper-api/features/custom-parser/writing-instructions-manually/parsing-instruction-examples.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## 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/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.
