如何获取网站分类/子分类各层级classname?解决四级报错问题
问题描述
我需要获取某连锁餐厅门店定位网站各层级元素的classname,网站结构分为3或4级,需逐层钻取:
- 第1级:初始页面显示各州链接
- 第2级:点击州后显示对应城市
- 第3级:点击城市后显示对应门店位置
- 第4级:点击门店后显示地址信息
当前我的Selenium代码可以获取前3级的classname,但第4级报错'NoneType' object is not subscriptable。我的逻辑是查找包含指定文本的锚点元素并获取其classname,禁止使用xpath。请帮忙优化代码,实现获取地址的classname,同时处理仅存在3级的场景(当城市仅有一个门店时为3级,多个门店时为4级)。
原代码如下:
from selenium import webdriver from selenium.webdriver.common.by import By import time # function to get url and class in different levels def get_url_class(url,level): driver.get(url) time.sleep(3) links = driver.find_elements(By.TAG_NAME, "a") for lnk in links: if level in lnk.text: if lnk.get_attribute("class"): new_class = lnk.get_attribute("class") new_url = lnk.get_attribute("href") return [new_class,new_url] # Open chromedriver driver = webdriver.Chrome() # Defining texts to search for each element state="Alabama" # --> Level #1 city="Huntsville" # --> Level #2 location="South Memorial Pkwy, Huntsville" # --> Level #3 address="11375 South Memorial Pkwy" # --> Level #4 initial_url = "https://locations.bojangles.com/" # Level #1 (Get state´s url and class) level1 = get_url_class(initial_url,state) print("className:" + level1[0] + ", url: "+ level1[1]) # Level #2 (Get cities´ url and class) level2 = get_url_class(level1[1],city) print("className:" + level2[0] + ", url: "+ level2[1]) # Level #3 (Get location's url and class) level3 = get_url_class(level2[1],location) print("className:" + level3[0] + ", url: "+ level3[1]) # Level #4 (Get address' url and class) level4 = get_url_class(level3[1],address) print("className:" + level4[0] + ", url: "+ level4[1]) driver.quit()
解决方案
问题根源
- 第4级页面的地址元素通常不是
<a>标签,原代码通过By.TAG_NAME, "a"找不到目标元素,函数返回None,后续访问level4[0]触发下标错误。 - 原代码未处理3级场景:当城市只有一个门店时,点击城市直接进入地址页面,不存在第3级门店列表。
优化后代码
from selenium import webdriver from selenium.webdriver.common.by import By import time def get_target_info(url, target_text, is_address=False): driver.get(url) time.sleep(3) if is_address: # 地址页面查找包含目标文本的地址元素(非链接) address_elements = driver.find_elements(By.CLASS_NAME, "Address-addressLine") for elem in address_elements: if target_text in elem.text: return [elem.get_attribute("class"), None] # 兜底备选类名 fallback_elements = driver.find_elements(By.CLASS_NAME, "c-address") for elem in fallback_elements: if target_text in elem.text: return [elem.get_attribute("class"), None] return [None, None] else: # 前3级查找带目标文本的链接 links = driver.find_elements(By.TAG_NAME, "a") for lnk in links: if target_text in lnk.text and lnk.get_attribute("href"): return [lnk.get_attribute("class"), lnk.get_attribute("href")] # 检查是否直接进入地址页面(3级场景) return get_target_info(url, target_text, is_address=True) # 初始化浏览器 driver = webdriver.Chrome() # 目标文本定义 state = "Alabama" # 第1级 city = "Huntsville" # 第2级 location = "South Memorial Pkwy, Huntsville" # 第3级 address = "11375 South Memorial Pkwy" # 第4级 initial_url = "https://locations.bojangles.com/" # 逐层获取信息 level1 = get_target_info(initial_url, state) print(f"第1级 className: {level1[0]}, url: {level1[1]}") level2 = get_target_info(level1[1], city) print(f"第2级 className: {level2[0]}, url: {level2[1]}") # 处理3级/4级分支逻辑 if level2[1]: level3 = get_target_info(level2[1], location) print(f"第3级 className: {level3[0]}, url: {level3[1]}") if level3[1]: level4 = get_target_info(level3[1], address, is_address=True) print(f"第4级 className: {level4[0]}") else: print(f"当前为3级结构,地址className: {level3[0]}") else: print(f"当前为3级结构,地址className: {level2[0]}") driver.quit()
优化说明
- 拆分地址级处理:针对地址元素非链接的特性,直接通过常见地址类名查找目标元素,规避xpath。
- 自动适配3级场景:如果某一级返回的
next_url为None,判定已进入地址页面,直接返回地址元素classname。 - 增加兜底逻辑:补充备选地址类名查找,提升页面结构变化时的兼容性。
- 分支逻辑清晰:通过
is_address参数区分普通链接级和地址级的处理逻辑。
内容的提问来源于stack exchange,提问作者Rasec Malkic
相关产品推荐
相关产品推荐

