Documentation has been updated: see help center and changelog in one place.

解析指令示例

查看 Oxylabs 自定义解析器的解析指令实用示例:处理嵌套对象、列表、错误和数组的数组等。

本文档展示了 自定义解析器 的示例用例。

下面的 HTML 片段将使用接下来的章节中的示例解析指令进行解析。

示例 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">袜子</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>

最低限度

用例:你想从所有 shoes description items.

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

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

xpath 函数将找到单个项并将其作为字符串放入列表:

{
    "shoes_description": [
        "Super"
    ]
}

确切的 xpath 函数行为已在此处描述 此处.

嵌套解析指令

用例:你想解析与鞋子相关的所有信息。此外,解析结果应表示所提供 HTML 的文档结构。

你正在定位示例 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>

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

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

解析指令如下所示。

示例 2。使用解析指令解析 shoes 信息。

{
    "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类似,但它不是返回所有匹配项的列表, 而是返回第一个匹配的项.

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

shoes 指令作用域没有定义管道(_fns 属性缺失)。这意味着在 title, 价格,以及 description 作用域中定义的管道将使用正在解析的文档作为管道输入。

在示例 2 中,你可以看到在 XPath 表达式中重复出现 //div[@id='shoes'] 这种重复可以通过在 shoes 作用域中定义管道来避免:

示例 3。在 shoes 作用域指令中定义管道以避免 XPath 表达式重复。

{
    "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 管道,该管道将输出 shoes HTML 元素;

  2. 获取 shoes._fns 管道输出并将其用作在 title, 价格,以及 description 作用域中定义的管道的输入;

  3. 处理 title, 价格,以及 description 这些管道以产生最终值。

结果看起来将与示例 2 的结果相同:

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

示例 2 与示例 3 的主要区别在于在示例 3 中,管道是在 shoes 作用域中定义的。 这个额外的管道选择了 shoes 的元素并将其传递给指令层级中更深处的后续管道。

嵌套对象列表

用例: 之前,你只想解析 shoes 信息。现在你想解析 HTML 中所有产品的信息。

示例 HTML 再次将 用作正在解析的文档。

如果你希望解析结果如下:

{
    "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 文档中发现的所有产品。

{
    "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 in products._fns 管道。 products._fns 该管道现在将输出与提供的 XPath 表达式匹配的所有元素的列表(产品元素的列表)。

  2. _items 保留属性用于指示你想通过迭代 products._fns 管道输出的每个项来形成列表并且 分别传递/处理每个列表项 沿着管道作用域向下。

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

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

从列表中选择第 N 个元素

本节演示了管道的灵活性。同一问题可以用不同方式解决。

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

用例: 你想从页面中选择第二个产品的价格。

示例 HTML 再次使用 作为示例。你有多种选择来选择第 2 个产品。

选项 1

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

示例 5。使用 XPath [] 选择器选择第二个价格。

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

结果:

{
    "second_price": [
        "60.12"
    ]
}

选项 2

你也可以使用 xpath 函数查找所有价格并将其通过管道传递给函数 select_nth,该函数从提取的价格列表中选择第 n 个元素。

示例 6。使用 `select_nth` 函数选择第 2 个值。

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

结果:

{
    "second_price": "60.12"
}

选项 3

您可以使用 select_nth 适用于任何列表类型,包括 HTML 元素列表:

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

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

结果:

{
    "second_price": ["60.12"]
}

错误处理

当给出以下 HTML 片段时:

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

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

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

自定义解析器将返回一个解析结果,其中 价格title 已正常解析,但由于 description 未能解析, convert_to_float 函数未能将 字符串 到达 float:

{
    "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" 参数来压制警告/错误:

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

这将产生以下结果:

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

数组的数组

自定义解析器允许在解析结果中使用 N 维数组。作为示例,我们使用以下 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 的二维整数数组:

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

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

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

最后更新于

这有帮助吗?