根本原因是页面使用动态渲染或异步加载导致dom未生成;requests只能获取原始html,需用selenium等工具处理js渲染内容,注意编码、大小写、等待条件及解析器差异。

Chrome审查元素时,Elements面板里点不动、选不中目标节点?
根本原因往往是页面用了动态渲染(比如 React/Vue),或者目标内容由 JS 异步加载,此时 DOM 树还没生成,你看到的只是初始 HTML 骨架。
实操建议:
- 先在
Network面板刷新页面,过滤XHR或Fetch,找返回 HTML 片段或 JSON 数据的请求——爬虫真正该抓的可能不是首页 HTML,而是这个接口 - 在
Elements面板右键任意节点 →Break on→subtree modifications,再触发页面变化(如点击“加载更多”),断点会停在 JS 插入新节点的位置,立刻定位动态更新逻辑 - 别只盯着
html标签右键“Copy selector”,它常生成脆弱的路径(如#app > div:nth-child(2) > ul > li:first-child),换用右键“Copy → Copy XPath”更稳定,但也要人工核对是否含动态 class 名(如class="item__2Kx9")
用 requests + BeautifulSoup 解析时,明明元素在审查工具里可见,但 soup.find() 找不到
这是最典型的“渲染 vs 源码”混淆。浏览器显示的是 JS 运行后的最终 DOM,而 requests.get() 拿到的只是服务器返回的原始 HTML 字符串,里面没有 JS 渲染后的内容。
判断方法:
- 右键网页 →
View Page Source,搜索你要找的文本,如果搜不到,说明它来自 JS 渲染,requests+BeautifulSoup就不适用 - 如果源码里有,但
find()失败,检查编码:用r = requests.get(url); r.encoding = r.apparent_encoding再解析,中文乱码会导致匹配失败 - 标签名大小写敏感:
soup.find('div', class_='content')不能写成class='Content';class 是多值属性,用class_='xxx'而非class_='xxx yyy'(后者只匹配完全相等),应改用class_=re.compile(r'xxx')
想用 Selenium 等待元素出现,WebDriverWait 总超时?
不是等待时间设太短,而是没选对等待条件。默认 presence_of_element_located 只管元素是否插入 DOM,不管是否可交互或可见。
常见场景对应写法:
- 等按钮可点击(有
onclick或监听器):用element_to_be_clickable - 等文字内容加载完成(比如异步填充的
span):用text_to_be_present_in_element,传入元组(By.XPATH, '//span'), '预期文本' - 等某个 class 被 JS 动态添加(如
loading类消失):用invisibility_of_element_located - 切记:所有等待都基于当前
driver的 DOM 快照,如果页面跳转或 iframe 切换,必须重新指定上下文(如driver.switch_to.frame())
用 lxml 的 etree.HTML() 解析,和 BeautifulSoup 结果不一致?
lxml 更严格遵循 HTML 标准,会自动修正错误嵌套(比如把 <p></p>
<div> 改为 <code><p></p>
<div>),而 <code>BeautifulSoup 默认用 html.parser 更宽容,保留原结构。
影响实际提取:
- 如果目标节点被
lxml“修复”移位,XPath 会失效,改用cssselect或先用etree.tostring()看它实际生成了什么 DOM -
lxml不支持部分 CSS 选择器(如:nth-of-type),但支持完整 XPath 表达式,性能通常比BeautifulSoup高 3–5 倍,适合大数据量批量解析 - 遇到自闭合标签(如
<img>),lxml默认按 XML 规则处理,若源码是 HTML4 风格(<img>),需加参数parser=etree.HTMLParser()
动态内容、编码陷阱、等待条件误用、解析器差异——这些不是配置问题,是网页本身构造方式带来的必然约束。盯住“源码有没有”“JS 执行没执行”“DOM 当前状态是什么”,比记住函数名重要得多。











