Playwright是处理动态网页最稳方案之一,因能真实启动浏览器、执行JS、等待加载并模拟交互,而requests+BeautifulSoup无法获取JS渲染内容;需禁用自动化标记、覆盖navigator属性、设置User-Agent等反爬参数,并用wait_for_selector/wait_for_response/wait_for_function精准等待,避免time.sleep或过早解析。

Playwright 是目前处理动态网页最稳的方案之一,它能真实启动浏览器、执行 JS、等待加载完成、甚至模拟用户交互,比 Selenium 轻量,API 更现代,跨浏览器支持也更统一。
为什么不用 requests + BeautifulSoup 抓动态页
因为很多页面内容由 JavaScript 动态插入(比如通过 fetch 或 axios 请求数据后渲染),requests 只拿到初始 HTML,里面没有目标数据;BeautifulSoup 解析的只是“空壳”。常见现象包括:关键列表为空、字段全是 None、抓到的 div 里只有 loading 动画。
- 页面依赖
window.__INITIAL_STATE__或类似全局变量 → 静态请求拿不到 - 内容在
scroll或click后才加载 → 需真实触发事件 - 有反爬检测(如
navigator.webdriver)→ Playwright 默认开启无头模式但暴露特征,需手动关闭
Playwright 启动浏览器时必须加的参数
不加这些,大概率被识别为自动化工具,直接返回 403 或空白页:
- 禁用自动化标记:
chromium.launch(headless=True, args=["--disable-blink-features=AutomationControlled"]) - 覆盖 navigator 属性(JS 层):
page.add_init_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})") - 设置真实 User-Agent:
page.set_extra_http_headers({"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36..."}) - 可选:禁用图片加载提速(非必需):
args=["--blink-settings=imagesEnabled=false"]
等待动态内容加载完成的正确写法
别用 time.sleep(),也别只等 DOM 就结束。要等目标元素“真正可见且有内容”:
立即学习“Python免费学习笔记(深入)”;
- 等某个元素存在并可见:
page.wait_for_selector("article.list-item", state="visible", timeout=10000) - 等网络请求完成(适合接口驱动型页面):
page.wait_for_response(lambda r: "api/list" in r.url and r.status == 200) - 等 JS 变量就绪(如 Vue/React 注入的数据):
page.wait_for_function("window.__DATA__ && window.__DATA__.items.length > 0") - 避免用
page.content()立即解析 —— 改用page.inner_html("main")或page.eval_on_selector("h1", "el => el.innerText")获取实时渲染结果
从 Playwright 切回 BeautifulSoup 做二次解析是否可行
可以,但要注意时机和方式。直接 BeautifulSoup(page.content(), "html.parser") 容易拿到未执行 JS 的快照;应该先确保页面已稳定,再取 page.inner_html("body") 或完整 page.content()。
更推荐的做法是:用 Playwright 自带的 page.query_selector() 和 page.query_selector_all() 提取结构化数据,它们底层已处理了 Shadow DOM、iframe 和异步更新,比丢给 BS4 更可靠。
如果真要用 BS4(比如习惯写 CSS 选择器或需要正则清洗),务必确认你取的是 page.inner_html() 而不是初始响应体 —— 这个细节漏掉,整个流程就白跑了。


















