菜单未加载是因HTTP客户端无法触发mouseover事件,需用Selenium/Playwright模拟真实浏览器交互,配合显式等待、滚动定位、可见性校验及上下文复用。
菜单没加载出来,是因为没触发
事件
浏览器里鼠标悬停(
)才拉取子菜单数据,但 Requests 这类纯 HTTP 客户端根本不会发这个事件,也没 DOM 树可“悬停”。直接请求页面 HTML,
里空空如也,不是你 selector 写错,是压根没加载。
实操建议:
立即学习
“
Python免费学习笔记(深入)
”;
用
或
启动真实浏览器环境,才能模拟真实交互
别依赖
等固定时间,改用显式等待:
悬停后要等子菜单 DOM 出现、且
或
生效,否则可能拿到空节点
的
不生效?检查元素是否在视口内
如果目标菜单项在滚动区域外(比如二级导航藏在顶部 fixed bar 下方),
会静默失败——它不自动滚动,也不报错。
实操建议:
立即学习
“
Python免费学习笔记(深入)
”;
先用
把元素滚进可视区
再执行
验证是否成功:悬停后立刻查
,看有没有
或
类名
用
更稳,但要注意
的默认超时和重试逻辑
的
默认带 5 秒超时 + 自动重试,看似省心,但容易掩盖问题:比如 selector 匹配到多个元素,它会 hover 第一个(未必是你想要的);或者元素被遮挡,hover 失败却因重试而延迟返回。
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
实操建议:
立即学习
“
Python免费学习笔记(深入)
”;
加明确的定位约束:
,避免模糊匹配
禁用自动重试,自己控制流程:
hover 后立刻用
断言,比单纯等时间更可靠
爬完多级菜单后,别直接关浏览器——小心连接复用失效
很多网站菜单接口是带 session 或 token 的,靠浏览器上下文维持。如果你 hover 拿到子菜单 URL 后,切回
去请求,大概率 403 或空响应,因为没传 cookie、没带 referer、没复用 WebSocket 连接。
实操建议:
立即学习
“
Python免费学习笔记(深入)
”;
整个链路保持在同一个
实例里完成:hover → 获取子菜单链接 →
如果必须切 Requests,至少导出当前页的
和
(尤其是
和
)
注意部分菜单是 fetch 加载的 JSON,得监听
捕获 XHR,而不是只看 HTML 结构
多级菜单的“悬停”本质是状态机:触发 → 渲染 → 可见 → 可交互。漏掉任一环,拿到的都是假数据。最常被忽略的是“可见性判断”——DOM 存在 ≠ 菜单已展开,得查样式或类名,不能只靠
不报错就认为成功。
mouseovermouseoverulSeleniumPlaywrighttime.sleep()WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".submenu")))display: blockvisibility: visibleActionChainsmove_to_elementmove_to_elementdriver.execute_script("arguments[0].scrollIntoView(true);", menu_item)ActionChains(driver).move_to_element(menu_item).perform()menu_item.find_element(By.CLASS_NAME, "submenu").get_attribute("class")showopenPlaywrighthoverPlaywrightpage.hover(selector)page.locator("nav > ul > li:has-text('产品')").hover()await page.locator(selector).hover({ timeout: 3000 })locator(".submenu").is_visible()RequestsPagepage.goto(submenu_url)cookiesheadersRefererUser-Agentpage.on("response", ...)find_element