You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用XPath和Python正确提取指定层级ul/li的菜单项

提取Level-2菜单的两种可行方案

先放你提供的简化HTML结构作为参考:

简化HTML结构示例:

<ul class="level-1">
  <li>
    <a href="/home">首页</a>
    <ul class="level-2">
      <li>
        <a href="/product">产品中心</a>
        <ul class="level-3">
          <li><a href="/product/1">产品1</a></li>
          <li><a href="/product/2">产品2</a></li>
        </ul>
      </li>
      <li><a href="/about">关于我们</a></li>
    </ul>
  </li>
</ul>

一、用精准XPath直接提取

之前踩坑大概率是没限定「直接子节点」,导致把level-3的后代li也误选进来了。以下是两种场景的实用XPath:

场景1:提取所有Level-2下的li的a标签(不管该li有没有子菜单)

用直接子节点选择器>,只选level-2 ul的直接子li,再取里面的a:

//ul[contains(@class, 'level-2')]/li/a

场景2:只提取没有Level-3子菜单的Level-2 li的a标签

加not()条件过滤掉带level-3子菜单的li:

//ul[contains(@class, 'level-2')]/li[not(ul[@class='level-3'])]/a

Python代码示例(基于lxml)

from lxml import etree

# 假设html_str是你的原始HTML内容
html_tree = etree.HTML(html_str)
# 用场景1的XPath提取所有符合要求的a标签
level2_items = html_tree.xpath("//ul[contains(@class, 'level-2')]/li/a")

# 整理成目标格式
result = []
for a_tag in level2_items:
    result.append({
        "name": a_tag.text.strip() if a_tag.text else "",
        "href": a_tag.get("href")
    })

print(result)

二、临时移除Level-3子菜单再提取

如果XPath总是搞混,干脆先把所有level-3的ul从DOM里删掉,再提取就不会有干扰了,用BeautifulSoup实现很直观:

from bs4 import BeautifulSoup

soup = BeautifulSoup(html_str, "lxml")

# 找到所有level-3的ul并彻底移除
for level3_ul in soup.find_all("ul", class_="level-3"):
    level3_ul.decompose()

# 现在直接提取level-2下的li的a标签即可
level2_links = soup.select("ul.level-2 > li > a")

result = []
for a_tag in level2_links:
    result.append({
        "name": a_tag.get_text(strip=True),
        "href": a_tag.get("href")
    })

print(result)

这个方法逻辑简单,完全避免了子层级的干扰,适合结构复杂的菜单场景。

内容的提问来源于stack exchange,提问作者John Boe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 08:53:16