requests + beautifulsoup 无法获取动态加载内容,因其仅获取原始html,不执行javascript;而playwright可启动无头浏览器渲染页面,配合等待策略与特征伪装,稳定抓取js生成内容。

为什么 requests + BeautifulSoup 拿不到动态加载的内容
因为 requests 只发 HTTP 请求,拿到的是服务器返回的原始 HTML,而页面中由 JavaScript 执行后才插入的 DOM 节点(比如滚动加载的商品列表、登录后的用户信息)根本不在这个原始 HTML 里。你用 BeautifulSoup 解析它,自然查不到 document.querySelectorAll('.item') 对应的元素。
常见现象包括:find_all() 返回空列表、关键字段始终为 None、抓取结果和浏览器开发者工具 Network → HTML 响应不一致。
这不是代码写错了,是技术选型错位——静态解析器无法执行 JS。
用 Playwright 启动无头 Chromium 是最稳的方案
Playwright 比 Selenium 更轻、启动更快、API 更一致,且默认支持等待网络空闲和元素出现,适合多数爬虫场景。
安装与基础用法:
pip install playwright playwright install chromium
关键实操建议:
- 用
page.goto(url, wait_until="networkidle")替代简单goto(),避免因异步请求未完成就提前解析 - 显式等待目标元素:用
page.wait_for_selector(".product-list li", timeout=10000),而不是time.sleep() - 获取渲染后 HTML:用
page.content(),不是page.inner_html("body")(后者可能漏掉 head 或 script 标签) - 关闭自动等待 JS 执行:
page.set_default_timeout(15000)防止单页卡死影响整个流程
什么时候该切回 requests + API 逆向
如果目标网站结构清晰、JS 渲染只是调用固定接口(比如 /api/items?page=2),直接模拟请求比启浏览器快 5–10 倍,也更稳定。
判断方法:
- 打开浏览器开发者工具 → Network → 切到 XHR/Fetch,刷新页面,找带分页参数或 JSON 响应的请求
- 检查该请求是否带
Cookie或X-Requested-With等 header;若有,用requests.Session()复现即可 - 注意部分接口会校验
Referer或User-Agent,需一并带上 - 若接口返回数据含加密字段(如
data: "a1b2c3..."),说明有前端加解密逻辑,此时 Playwright 更省事
别忽略反爬对 Playwright 的干扰
很多网站会检测 webdriver、navigator.webdriver、chrome.runtime 等特征,直接返回 403 或空白页。
绕过要点:
- 启动时加
chromium.launch(headless=True, args=["--disable-blink-features=AutomationControlled"]) - 注入 JS 清除特征:
page.add_init_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") - 禁用图片/字体加载可提速:
page.route("**/*.{png,jpg,svg,woff,ttf}", lambda route: route.abort()) - 不要复用同一
browser实例跑大量不同域名请求,容易触发行为风控
真实环境里,JS 渲染页的难点往往不在“怎么等”,而在“等到了之后,怎么不被识破”。特征抹除必须做,而且得做全。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











