requests只能获取原始html,因目标内容由javascript动态渲染生成,而原始html中仅含空壳结构(如),无实际数据;需用selenium或playwright启动真实浏览器执行js并等待渲染完成后再提取dom。

因为 requests 只拿原始 HTML,而目标内容由 JavaScript 渲染生成——你看到的页面和服务器返回的源码根本不是一回事。
requests.get() 拿到的 HTML 里根本没有目标标签
现代网页大量使用前端框架(React/Vue/Angular)或 AJAX 加载数据,requests 发起 HTTP 请求后,只收到一个“空壳” HTML:里面可能只有 <div id="app"></div> 或几行 JS 脚本,真实内容还没生成。这时候用 BeautifulSoup 去找 class="price" 或 id="list",自然返回 None 或空列表。
- 用浏览器打开目标页 → 右键「查看网页源代码」→ 搜索你要的内容关键词,如果搜不到,基本就是动态渲染
- 对比「开发者工具」→ 「Elements」标签页里的 DOM 结构,它经过 JS 执行后已被修改,但
requests拿不到这个版本 - 直接打印
r.text[:500],确认返回内容是否真的缺失目标标签
用 Selenium / Playwright 替代 requests 获取真实渲染后的 HTML
这类工具启动真实浏览器(或无头模式),执行 JS,等页面加载完成再提取 DOM,才能拿到你看到的内容。
-
Selenium示例中必须加显式等待(如WebDriverWait),不能只靠driver.implicitly_wait(),否则可能仍取到未渲染完的中间状态 -
Playwright对异步加载支持更稳,且默认等待网络空闲,比 Selenium 更少踩坑 - 避免用
driver.page_source后再丢给BeautifulSoup解析——直接用driver.find_element(By.CSS_SELECTOR, "...")提取更可靠 - 注意 ChromeDriver / FirefoxDriver 版本需与浏览器匹配,否则
WebDriverException报错时返回空内容
tbody 标签在 XPath 或 CSS 选择器里是隐形陷阱
浏览器开发者工具里复制的 XPath 经常带 /tbody,但原始 HTML 源码里往往没有这个标签——它是浏览器自动补全的,lxml 或 BeautifulSoup 解析原始 HTML 时不认它。
- 检查原始 HTML 源码(右键 →「查看网页源代码」),搜索
<table> 后是否真有 <code><tbody>;没有就删掉 XPath 中的 <code>/tbody - CSS 选择器同理:
table tbody tr改成table tr更稳妥 - 用
soup.select("table tr")比soup.find_all("tr", {"parent": "tbody"})更直接,也避开 tbody 争议 - 必须设置
User-Agent,最好再加Accept、Accept-Language、Sec-Ch-Ua等现代浏览器 header 字段 - 某些站点依赖 Cookie 或 Referer,比如先 GET 首页拿到
Set-Cookie,再带着它请求数据接口 - 遇到
<noscript><meta http-equiv="refresh" ...></noscript>,说明服务端识别出无 JS 环境,直接降级返回了 fallback 页面
headers 和请求上下文缺失导致服务端返回简化版或拦截页
有些网站检测到非浏览器请求,会返回空白页、跳转页(如含 <script>location.replace(...) </script>)或反爬中间页,此时 r.text 看似正常,实则没数据。
真正麻烦的不是“怎么让内容出来”,而是判断它到底卡在哪一层:是没发出去请求?发出去但被拦了?拦过去但没执行 JS?JS 执行了但数据藏在 XHR 里?每一步都得用对应手段验证,而不是盲目换库或加 delay。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











