Python Playwright 自动化实战:SPA 页面抓取、短信验证码登录与跨域登录态保持

举报
yd_269200205 发表于 2026/10/22 23:53:28 2026/10/22
【摘要】 以一次真实自动化实践为例,介绍用 Python Playwright 解决三大典型难题:SPA 页面抓取(networkidle 与 JS 点击兜底)、短信验证码登录(常驻浏览器 + 文件信号量)、跨域登录态同步(storage_state 与 CAS 单点登录)。附完整可运行代码与踩坑记录。

一、背景

很多现代网站(如华为云开发者成长中心)是纯 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() 经常超时。排查思路分两步:

  1. 枚举页面元素确认元素真实存在:
btns = page.eval_on_selector_all(
    "button, div, span",
    "els => els.filter(e => e.offsetParent !== null)"
       ".map(e => ({tag: e.tagName, cls: e.className}))"
)
  1. 用 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 场景,欢迎交流。)

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。