如何用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
相关产品推荐
相关产品推荐

