基于Playwright的智慧树课程自动化学习脚本开发实践

📅 2026/7/23 10:17:14 👁️ 阅读次数 📝 编程学习
基于Playwright的智慧树课程自动化学习脚本开发实践

1. 项目概述与核心需求解析

最近在技术社群里,经常看到有朋友在讨论如何“解放双手”,特别是针对一些需要长时间挂机、重复点击的在线学习任务。智慧树作为国内广泛使用的在线课程平台,其课程学习通常包含视频观看、章节测验等环节,这些环节往往耗时且操作固定。手动完成不仅枯燥,还容易因忘记操作而中断学习进度。因此,一个能够模拟用户行为、自动完成课程学习的脚本,其需求就变得非常具体和迫切。

这个项目,本质上是一个基于浏览器自动化的“机器人”。它不是为了攻击或破坏系统,而是在用户授权和监督下,模拟一个真实学习者的操作流程:打开浏览器、登录账号、进入课程、播放视频、完成课后习题。其核心价值在于将用户从重复、机械的点击操作中解放出来,把时间留给更需要创造性思考和深度学习的环节。当然,任何自动化工具的使用都必须严格遵守平台的使用条款,本项目的分享旨在探讨Playwright这一现代自动化框架的技术实现,供学习者研究参考,切勿用于任何违规用途。

从技术选型上看,之所以选择Python + Playwright的组合,是因为它几乎是为这类Web自动化任务量身定做的。Python语法简洁,生态丰富;而Playwright由微软开源,支持Chromium、Firefox和WebKit三大浏览器引擎,且API设计非常现代和人性化。相比传统的Selenium,Playwright在自动等待、网络拦截、移动端模拟等方面有着显著优势,编写出来的脚本更稳定、更健壮。接下来,我将详细拆解这个项目的设计思路、关键实现步骤以及我趟过的那些“坑”。

2. 技术选型与环境搭建思路

为什么是Playwright?这是一个必须首先回答的问题。在Web自动化领域,我们有几个常见选择:Selenium、Puppeteer和Playwright。Selenium历史悠久,生态庞大,但配置相对繁琐,且对于动态页面的等待处理需要开发者投入更多精力。Puppeteer是Chrome官方团队出品,对Chrome/Chromium的支持堪称完美,但早期只支持JavaScript,且对其他浏览器支持有限。

Playwright则可以看作是Puppeteer的“升级版”和“多平台版”。它由原Puppeteer团队的核心成员开发,继承了其优良基因,并进行了大量改进。其核心优势在于:

  1. 跨浏览器支持:一套API可控制Chromium、Firefox和WebKit,对于需要测试页面兼容性的场景非常有用。虽然我们这里只针对智慧树(通常用Chrome内核访问即可),但这意味着技术栈的通用性更强。
  2. 自动等待:这是Playwright最令人称道的特性之一。在定位元素或执行点击前,它会自动等待元素达到可操作状态(如可见、可点击、稳定等),这极大地减少了编写显式等待(time.sleep)代码的需要,让脚本更加稳定。
  3. 强大的网络控制:可以轻松地拦截和修改网络请求,这对于处理视频播放心跳、提交答案等场景非常关键。
  4. 丰富的设备模拟:内置了大量移动设备(如iPhone、Pixel)的视口、User-Agent等参数,可以方便地模拟移动端访问。

基于以上几点,Playwright在开发效率和脚本稳定性上,对于此类自动化任务具有明显优势。项目提供了“免安装版”,这通常意味着作者已经将Python解释器、Playwright库以及必要的浏览器驱动打包成了一个可执行文件(例如使用PyInstaller),用户无需配置Python环境即可运行,这对非技术用户非常友好。

2.1 本地开发环境搭建

如果你想自己研究或修改脚本,就需要搭建本地开发环境。过程并不复杂。

首先,你需要安装Python。建议使用Python 3.8及以上版本。可以从Python官网下载安装包,安装时务必勾选“Add Python to PATH”,这样才能在命令行中直接使用pythonpip命令。

安装完成后,打开命令行(CMD或PowerShell),通过pip安装Playwright库:

pip install playwright

安装完成后,还需要安装Playwright所需的浏览器内核。Playwright提供了一个非常方便的命令来完成这件事:

playwright install

这条命令会下载Chromium、Firefox和WebKit的二进制文件。由于我们主要使用Chromium,如果你希望节省时间和磁盘空间,可以只安装Chromium:

playwright install chromium

至此,核心的开发环境就准备好了。你可以创建一个新的Python文件(例如zhihuishu_auto.py)开始编写代码。

注意:在某些网络环境下,playwright install下载浏览器可能会非常慢甚至失败。这时可以考虑使用镜像源,或者在Playwright的配置中指定离线已下载的浏览器路径。不过对于大多数用户,耐心等待或切换网络即可。

3. 核心功能模块设计与实现拆解

一个完整的智慧树刷课脚本,可以分解为以下几个核心模块,它们串联起来形成了一个完整的自动化工作流。

3.1 用户认证与登录模块

这是脚本的起点,也是最容易出问题的地方之一。智慧树的登录页面可能涉及用户名/密码输入、验证码、甚至滑块验证。

实现思路

  1. 启动浏览器上下文:使用Playwright创建一个浏览器实例,并建议启用“有头模式”(headless=False)进行初期调试,这样你能直观地看到浏览器的操作过程。
    from playwright.sync_api import sync_playwright with sync_playwright() as p: # 启动Chromium浏览器,非无头模式便于调试 browser = p.chromium.launch(headless=False) # 创建一个新的浏览器上下文(类似于一个独立的会话窗口) context = browser.new_context() page = context.new_page()
  2. 导航至登录页:使用page.goto()方法打开智慧树登录页面。
  3. 填充登录信息:定位用户名和密码输入框。这里就需要用到Playwright的定位器(Locator)。智慧树的页面结构可能会变,所以需要通过浏览器开发者工具(F12)来查看当前输入框的HTML属性(如id、class、name等)。
    # 假设通过查看元素,发现用户名输入框的id是‘lUsername’ page.locator('#lUsername').fill('你的学号') page.locator('#lPassword').fill('你的密码')
  4. 处理验证码:这是难点。如果遇到图形验证码,简单的自动化脚本很难识别。可能的解决方案有:
    • 手动介入:在脚本中设置一个等待,提示用户手动输入验证码后再继续。
    • 第三方OCR服务:接入付费或免费的OCR API进行识别,但这会增加复杂性和成本。
    • 观察规律:有些网站的验证码在短时间内同一IP或会话下不会频繁更换,可以尝试先手动登录一次,脚本保存cookies,后续使用cookies恢复会话来跳过登录。Playwright的context.storage_state()方法可以非常方便地保存和加载cookies及本地存储。
    # 首次手动登录后保存状态 context.storage_state(path="state.json") # 下次运行脚本时,直接加载状态,可能无需再次登录 context = browser.new_context(storage_state="state.json") page = context.new_page() page.goto("https://passport.zhihuishu.com/") # 直接跳转已登录后的页面
    实操心得:强烈推荐使用“保存登录状态”的方式。首次运行脚本时,用headless=False模式手动完成登录(包括处理任何验证码),然后让脚本保存状态文件。之后运行脚本时,直接加载这个状态文件,绝大多数情况下都可以直接进入已登录状态,完美绕过登录难题。

3.2 课程导航与章节遍历模块

登录成功后,脚本需要找到目标课程,并进入学习界面。智慧树的课程列表通常在一个“我的课程”或“学习空间”页面。

实现思路

  1. 等待页面加载:登录后跳转的页面可能是一个门户,需要等待关键元素(如“我的课程”链接)出现。使用Playwright的page.wait_for_selector()或直接使用Locator的wait_for()方法。
    # 等待“我的课程”这个元素出现,假设它是一个链接,文本内容是“我的课程” page.locator('text=我的课程').wait_for() page.locator('text=我的课程').click()
  2. 定位目标课程:课程列表可能是动态加载的。需要找到包含目标课程名称的元素并点击。这里定位器的文本匹配功能非常有用。
    # 点击课程名为“大学计算机基础”的课程卡片 page.locator('text=大学计算机基础').click()
  3. 进入学习进度页面:进入课程后,通常需要点击“学习进度”或类似的标签页才能看到章节列表。
  4. 遍历章节:章节列表通常是一个树形结构或列表。需要编写逻辑来遍历每一个章节(或单元)。可以使用page.locator()获取所有章节项的列表,然后循环处理。
    # 假设每个章节项都有一个共同的类名 ‘chapter-item’ chapter_items = page.locator('.chapter-item') count = chapter_items.count() for i in range(count): item = chapter_items.nth(i) # 点击展开或进入章节 item.click() # 这里开始处理该章节下的视频和测验 # ... # 处理完后,可能需要返回章节列表页,或者页面本身就在当前章节内
    注意事项:页面操作(如点击章节)可能会触发动态加载或页面跳转。务必在关键操作后使用page.wait_for_load_state('networkidle')或等待特定元素出现,确保页面稳定后再进行下一步操作,这是脚本稳定性的关键。

3.3 视频播放与进度监控模块

这是刷课的核心。脚本需要自动播放视频,并确保视频计时进度被系统正确记录。

实现思路

  1. 定位视频播放器:进入具体章节后,找到视频播放器。它可能是一个<video>标签,也可能是基于Flash或H5的播放器。现代网站大多使用HTML5的<video>标签。
  2. 控制播放:Playwright可以直接与<video>标签交互。
    # 定位到video元素 video = page.locator('video') # 点击播放按钮(如果视频没有自动播放) video.click() # 或者通过执行JS来播放 page.evaluate('document.querySelector("video").play()')
  3. 监控进度与心跳:仅仅播放视频是不够的。智慧树后台通常会有“心跳”机制,定期向服务器报告学习进度,以防止纯粹的前端播放作弊。我们需要模拟这个行为。
    • 网络监听法(推荐):使用Playwright的page.on('request')事件监听器,捕获浏览器发出的所有网络请求。通过分析,找到那个周期性发送的、包含进度信息的“心跳”请求(通常是一个POST请求,URL包含heartBeatreport等关键词)。一旦找到,我们可以确保这个请求被正常发出,或者甚至可以直接用脚本模拟发送这个请求。
      def handle_request(request): if 'heartBeat' in request.url: print(f"捕获到心跳请求: {request.url}") # 可以在这里记录或不做处理,确保请求正常发出即可 page.on('request', handle_request)
    • 进度模拟法:如果找不到明确的心跳请求,可能需要模拟用户与视频的交互,如随机移动鼠标、轻微滚动页面等,让页面脚本认为用户正在活动。
  4. 处理弹题:视频播放过程中,可能会弹出随堂问题。脚本需要检测这些弹窗,并选择答案。
    # 监听弹题窗口的出现,假设弹题窗口有一个特定的类名 ‘popup-quiz’ try: quiz_popup = page.locator('.popup-quiz').wait_for(timeout=5000) # 等待5秒看是否出现 # 如果出现了,选择第一个答案(或根据逻辑选择) quiz_popup.locator('.answer-option').first.click() quiz_popup.locator('.submit-btn').click() except: # 没有弹题,继续 pass
    实操心得:视频播放部分最关键的挑战是“防作弊机制”。单纯的前端播放很容易被系统检测并判定为无效学习。通过网络请求监听来确保后台心跳的正常发送,是最有效、最接近真实用户行为的方式。务必花时间分析智慧树学习时的网络请求,找到那个关键的心跳接口。

3.4 章节测验自动答题模块

完成视频学习后,通常会有章节测验。自动化答题的复杂度取决于题目的类型。

实现思路

  1. 进入测验页面:点击“章节测验”或“去做题”按钮。
  2. 获取题目与选项:解析页面结构,提取题目文本和所有选项。这需要仔细分析测验页面的HTML。
    # 假设每个题目都包裹在一个类名为 ‘question-item’ 的div中 questions = page.locator('.question-item') for i in range(questions.count()): q = questions.nth(i) question_text = q.locator('.question-stem').inner_text() options = q.locator('.option-item') # 接下来需要根据题目文本决定如何选择答案
  3. 答题策略
    • 固定答案:如果题库固定,可以建立本地题库映射(题目文本 -> 答案)。
    • 搜索答案:将题目文本提取出来,通过浏览器打开一个新的标签页,使用搜索引擎(如百度)进行搜索,然后从搜索结果中提取最可能的答案。这涉及到更复杂的多页面控制和文本解析。
    • 随机选择:对于选择题,在没有更好策略时,随机选择一个选项。但这正确率低。
    • OCR识别(针对图片题):极少情况题目可能是图片,需要集成OCR功能。
  4. 提交答案:所有题目处理完毕后,点击提交按钮。并处理提交后的结果(如确认对话框)。
    page.locator('text=提交答案').click() # 处理可能的确认弹窗 page.on('dialog', lambda dialog: dialog.accept())
    注意事项:自动答题是脚本中风险较高的部分,因为可能涉及平台规则。且智慧树的题目可能更新,导致固定题库失效。搜索答案的策略虽然智能,但速度慢,且依赖于外部网络。请谨慎使用此功能,并优先考虑用于学习研究目的。

4. 脚本的健壮性处理与错误恢复

一个能长时间稳定运行的脚本,必须考虑各种异常情况。

4.1 元素定位失败处理

页面加载慢、元素动态生成都可能导致定位失败。不能使用固定的sleep,而应利用Playwright的自动等待和显式等待。

from playwright.sync_api import TimeoutError as PlaywrightTimeoutError try: # 显式等待某个关键元素最多10秒 element = page.locator('#critical-button').wait_for(timeout=10000) element.click() except PlaywrightTimeoutError: print("关键元素未在指定时间内出现,可能页面加载异常。") # 错误恢复策略:刷新页面,或者记录错误并跳过当前任务 page.reload() # 或者 break/continue 到下一个循环

4.2 网络异常与页面崩溃处理

脚本运行中可能遇到网络断开、页面崩溃(特别是长时间运行)。

# 监听页面崩溃事件 page.on('close', lambda: print("页面意外关闭!")) # 在实际操作中,可能需要将大的任务(如一门课)分解成小任务, # 并定期保存进度(如当前处理到的章节索引),以便崩溃后能从断点恢复。

4.3 登录状态失效处理

虽然使用了保存的状态,但登录会话可能过期。脚本需要检测是否被重定向到了登录页。

# 在执行某个操作前,检查当前页面是否还在登录状态 if "login" in page.url or page.locator('text=登录').is_visible(): print("检测到登录状态失效,尝试重新登录...") # 调用重新登录的函数,或者提示用户手动干预 relogin(page)

5. 免安装版封装与使用指南

对于不会Python环境的用户,“免安装版”极大地降低了使用门槛。这通常是通过PyInstallercx_Freeze等工具将Python脚本及其所有依赖(包括Python解释器)打包成一个独立的可执行文件(.exe)。

封装关键步骤

  1. 确保你的脚本在开发环境下运行无误。
  2. 安装PyInstaller:pip install pyinstaller
  3. 执行打包命令。一个典型的命令如下:
    pyinstaller --onefile --add-data "state.json;." --hidden-import playwright._impl._pywheel zhihuishu_auto.py
    • --onefile:打包成单个exe文件。
    • --add-data:将非代码文件(如保存登录状态的state.json)打包进去。
    • --hidden-import:确保Playwright的一些隐式依赖被包含。
  4. 打包完成后,在dist目录下会生成exe文件。这个文件可以复制到任何Windows电脑上运行,无需安装Python。

给最终用户的使用指南

  1. 首次运行:双击exe文件,会弹出一个命令行窗口和浏览器窗口。请勿关闭命令行窗口。在浏览器中手动完成智慧树登录(如果需要验证码,请手动输入)。登录成功、页面跳转到课程列表后,脚本通常会开始自动工作,或者按某个键(如回车)开始。首次运行后,脚本会在同级目录下生成一个state.json文件,保存了你的登录会话。
  2. 后续运行:只要state.json存在且登录未过期,再次运行exe时,脚本会直接使用保存的会话,无需再次手动登录。
  3. 注意事项:运行期间请保持电脑不休眠、不断网。关闭浏览器窗口或命令行窗口,脚本即停止。

重要提醒:使用任何自动化脚本都存在一定风险。智慧树平台用户协议中通常禁止任何形式的自动化程序访问。使用此类脚本可能导致学习记录被判定无效、账号受到限制等后果。本技术分享仅供学习和研究浏览器自动化技术之用,请务必谨慎评估使用风险,尊重平台规则。

6. 进阶优化与扩展思考

在实现了基本功能后,还可以从以下几个方面进行优化:

  1. 配置化:将账号、密码、目标课程名、学习速度(播放速率)等参数提取到外部的配置文件(如config.iniconfig.json)中,避免硬编码。
  2. 多账号与并发:使用Playwright的多个Browser Context,可以在同一个浏览器实例内实现多账号同时运行,相互隔离cookies。但这对电脑性能要求较高,且平台风控风险急剧增加,不推荐普通用户尝试。
  3. 图形用户界面(GUI):使用tkinterPyQtDearPyGui为脚本制作一个简单的图形界面,方便用户输入参数、查看运行日志和进度。
  4. 更智能的答题策略:集成一个轻量级的本地向量数据库(如SQLite+文本嵌入),将题目和答案存储起来,实现更高效、更准确的题库匹配。
  5. 日志与监控:完善日志系统,记录脚本运行的每一步,包括成功、失败、遇到的异常等,方便后期排查问题。

浏览器自动化是一个强大的工具,Playwright使得这一过程变得更加高效和可靠。通过这个项目,我们不仅解决了一个具体问题,更深入学习了现代Web自动化测试与爬虫的核心技术。记住,技术是把双刃剑,始终用在正当、合规的地方,才是长久之道。