Python Playwright 自动化实战:SPA 页面抓取、短信验证码登录与跨域登录态保持
一、背景
很多现代网站(如华为云开发者成长中心)是纯 JavaScript 渲染的单页应用(SPA),直接用 requests 抓取只能拿到一句 "Please enable JavaScript to continue"。本文以一次真实的自动化实践为例,完整介绍用 Python Playwright 解决 SPA 抓取、验证码登录、跨域登录态同步三个典型难题。
二、环境准备
pip install playwright
playwright install chromium
基础用法:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("https://example.com", wait_until="networkidle")
page.wait_for_timeout(3000) # 给 Vue/React 渲染留时间
print(page.inner_text("body"))
wait_until="networkidle" 会等到网络请求静默 500ms,是 SPA 抓取的关键参数。
三、难点一:iframe 与动态渲染的登录按钮
华为云的登录组件(HWID)在 iframe 中动态渲染,直接 locator.click() 经常超时。排查思路分两步:
- 枚举页面元素确认元素真实存在:
btns = page.eval_on_selector_all(
"button, div, span",
"els => els.filter(e => e.offsetParent !== null)"
".map(e => ({tag: e.tagName, cls: e.className}))"
)
- 用 JS 点击兜底。有些按钮被遮挡或处于动画中,Playwright 的可见性检查会失败,用
evaluate直接触发 DOM 事件最稳:
page.locator(".login-btn-primary").first.evaluate("e => e.click()")
实战中还遇到同页有两个同名按钮,一个 disabled 一个正常的情况,务必先检查 class 中的 disabled 再决定点哪个。
四、难点二:登录态的保存与复用
短信验证码登录成功后,把 Cookie 会话持久化,后续脚本免登录:
# 登录成功后保存
ctx.storage_state(path="auth_state.json")
# 新会话加载
ctx = browser.new_context(storage_state="auth_state.json")
注意 storage_state 保存的是当前 context 全部域的 Cookie。华为云账号体系(auth.huaweicloud.com)签发的会话,访问同体系站点(bbs.huaweicloud.com 等)时会自动走 CAS 单点登录,URL 上会带 ticket=ST-xxxx 参数完成免密跳转,无需额外处理。
验证登录态是否生效,不要只看 URL,要检查页面文本中是否出现用户名或"我的积分"等登录后才有的元素。
五、难点三:短信验证码绑定浏览器会话
这是最隐蔽的坑:验证码与发送时的浏览器实例绑定。我在会话 A 中点了"获取验证码",然后关闭浏览器,在会话 B 中填入同一个验证码,服务端直接返回"验证码不存在或已过期"。
解决方案是常驻浏览器 + 文件信号量:
# 长驻脚本:发码后轮询等待文件出现
page.locator(".get-auth-code").click()
code = None
for _ in range(540):
try:
code = open("sms_code.txt").read().strip()
if code: break
except FileNotFoundError:
time.sleep(1)
page.locator("input[placeholder='短信验证码']").fill(code)
page.locator(".login-btn").first.evaluate("e => e.click()")
外部(人或上游程序)验证码到达后写入 sms_code.txt,同一浏览器实例内完成登录,全程不重启进程。
六、其他实战经验
- 元素定位:优先
placeholder、class组合;SPA 的 DOM 层级不可靠; - 显式等待:
page.wait_for_url("**目标域**")判断登录跳转比 sleep 靠谱; - 截图调试:
page.screenshot()保存关键节点,headless 排查利器; - API 抓取替代:若只是要数据,可在 DevTools Network 里找到页面背后的 XHR 接口直接调用,往往比渲染整个页面快一个数量级。
七、结语
Playwright 对 SPA 的支持远强于传统方案,核心心法是:把浏览器当作真实用户对待——等它渲染、陪它等待、在同一个会话里完成敏感操作。跨域 SSO、验证码会话绑定这类"反自动化"设计,用常驻会话 + 信号量文件的模式都可以优雅化解。
(本文思路同样适用于 Selenium + ChromeDriver 场景,欢迎交流。)
- 点赞
- 收藏
- 关注作者
评论(0)