如何用Selenium或BeautifulSoup循环解析多级嵌套导航标签元素
电商网站多级菜单解析问题:无法获取完整三级菜单数据
问题背景
已用BeautifulSoup成功抓取一级、二级菜单,但三级菜单只能拿到每个子菜单的第一个项;Selenium的XPATH解析也未成功,目标是生成包含所有层级的DataFrame。
HTML示例
<ul class="c-nav-menu ''"> <li class="dropDown hoverFade topNav category-6 c-furniture "> <a class="c-nav-category_link topnav-furniture" href="xx"> <span>Furniture</span> </a> <div class="c-nav-columns hoverFadeTarget c-nav-columns-furniture "> <div class="c-nav-columns_group columns_group-size--5"> <div class="col col-0"> <div class="nav-columns-section-heading living-room-furniture">Living Room Furniture</div> <ul> <li> <a href="xx2"> Sofa & Sectional Collections
期望的DataFrame结构
| Category 1 | Category 2 | Category 3 | Category 3 Link Path |
|---|---|---|---|
| Furniture | Living Room Furniture | Sofas & Sectionals | https://www.xx./furniture/living_room/sofa |
| Furniture | Living Room Furniture | Chairs | https://www.xx./furniture/living_room/chairs |
| Furniture | Living Room Furniture | Coffee Tables | https://www.xx./furniture/living_room/coffee_table |
已尝试的代码及问题
1. 一级菜单(成功)
nav = soup.find_all("a", {"class" : lambda L: L and L.startswith('c-nav-category_link topnav')}) for item in nav: level1 = { 'cat_1': item.find("span").text} print(level1)
输出:
{'cat_1': 'Furniture'} {'cat_1': 'Outdoor & Garden'} {'cat_1': 'Rugs'}...
2. 三级菜单(仅返回每个子菜单第一个项)
final_link = soup.find_all("div", {"class" : lambda L: L and L.startswith('col col-')},"li") for final_item in final_link: level3 = { 'cat_3': final_item.find("a").text.replace('\n','')} print(level3)
输出:
{'cat_3': 'Sofa & Sectional Collections'} {'cat_3': 'Bedroom Collections'} {'cat_3': 'Dining Collections'}...
问题:只能拿到每个二级菜单下的第一个三级项,无法获取所有子项。
3. Selenium尝试(未成功)
from selenium.webdriver.common.by import By title = driver.find_elements(by=By.XPATH, value='//*[@id="topnav-container"]/ul/li') for li in title: product_data = {'title': li.text} print(product_data)
问题:仅输出最后一个一级菜单的文本,未遍历所有层级。
解决方案
方法一:使用BeautifulSoup完整遍历层级
核心思路:从一级菜单的父节点开始,逐层遍历二级、三级菜单,确保每个层级的所有子项都被抓取。
import pandas as pd from bs4 import BeautifulSoup # 假设已获取完整页面HTML内容并存入html变量 soup = BeautifulSoup(html, 'html.parser') menu_data = [] # 遍历每个一级菜单的li节点 for top_li in soup.select('ul.c-nav-menu li.dropDown'): # 获取一级菜单名称 cat1 = top_li.select_one('a.c-nav-category_link span').text.strip() # 找到当前一级菜单对应的下拉列表层 columns_container = top_li.select_one('div.c-nav-columns') if not columns_container: continue # 遍历每个二级菜单所在的col容器 for col in columns_container.select('div.col[class^="col col-"]'): # 获取二级菜单名称 cat2 = col.select_one('div.nav-columns-section-heading').text.strip() # 遍历当前二级菜单下的所有三级菜单项 for li in col.select('ul li'): a_tag = li.select_one('a') if not a_tag: continue # 获取三级菜单名称和链接 cat3 = a_tag.text.strip() cat3_link = a_tag['href'] # 若需转为绝对链接,可取消下方注释 # cat3_link = 'https://www.xx.com' + cat3_link # 添加到数据列表 menu_data.append({ 'Category 1': cat1, 'Category 2': cat2, 'Category 3': cat3, 'Category 3 Link Path': cat3_link }) # 转换为DataFrame df = pd.DataFrame(menu_data) print(df.head())
方法二:使用Selenium正确遍历多级菜单
核心思路:模拟鼠标悬停触发下拉菜单,逐层定位每个层级的元素,确保所有子项加载并被抓取。
import pandas as pd from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC driver = webdriver.Chrome() driver.get('你的电商网站URL') wait = WebDriverWait(driver, 10) menu_data = [] # 遍历所有一级菜单 top_menu_items = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, 'ul.c-nav-menu li.dropDown'))) for item in top_menu_items: # 鼠标悬停触发下拉菜单 ActionChains(driver).move_to_element(item).perform() # 获取一级菜单名称 cat1 = item.find_element(By.CSS_SELECTOR, 'a.c-nav-category_link span').text.strip() # 找到当前一级菜单的下拉容器 columns_container = item.find_element(By.CSS_SELECTOR, 'div.c-nav-columns') # 遍历所有二级菜单容器 col_elements = columns_container.find_elements(By.CSS_SELECTOR, 'div.col[class^="col col-"]') for col in col_elements: # 获取二级菜单名称 cat2 = col.find_element(By.CSS_SELECTOR, 'div.nav-columns-section-heading').text.strip() # 遍历所有三级菜单项 li_elements = col.find_elements(By.CSS_SELECTOR, 'ul li') for li in li_elements: a_tag = li.find_element(By.TAG_NAME, 'a') cat3 = a_tag.text.strip() cat3_link = a_tag.get_attribute('href') menu_data.append({ 'Category 1': cat1, 'Category 2': cat2, 'Category 3': cat3, 'Category 3 Link Path': cat3_link }) driver.quit() # 转换为DataFrame df = pd.DataFrame(menu_data) print(df.head())
内容的提问来源于stack exchange,提问作者newdev657
相关产品推荐
相关产品推荐

