ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Python自动化实践:基于Selenium与Requests的在线学习辅助工具开发

Python自动化实践:基于Selenium与Requests的在线学习辅助工具开发 简介本资源是一款面向高校师生的毕业设计级Python工具旨在辅助雨课堂RainClassroom在线学习场景下的自动化操作与信息管理解决课件下载、签到提醒、数据统计等高频重复性问题。压缩包共12个文件含7个核心Python模块如登录认证、主窗口交互、后台监控、工具函数封装等、1份依赖说明requirements.txt、1份项目说明文档README.md、1张界面示意图jpg、1个图标文件ico及基础配置文件整体仅111KB轻量易部署。已有69人学习下载适合具备Python基础的本科生开展课程设计或教学辅助开发实践。读者可直接运行主程序RainClassroomAssistant.py获得完整GUI交互界面代码结构清晰分层涵盖UI、业务逻辑、工具类与配置模块便于理解在线教育平台接口调用逻辑、PyQt5桌面应用开发范式及多线程监控实现思路。1. 项目概述与核心价值最近在整理自己的学习资料库翻到了一个几年前写的、名为“基于Python的雨课堂在线学习辅助工具.zip”的老项目。这个压缩包的名字听起来可能有点“技术黑话”的味道但说白了它就是一个用Python写的小脚本集合专门用来辅助处理在“雨课堂”这个在线学习平台上遇到的一些重复性、机械性的操作。比如自动签到、批量下载课件、整理课程公告甚至是模拟完成一些简单的课后互动任务。为什么现在又把它翻出来讲因为我发现无论是几年前还是现在在线学习平台的使用体验里总有一些“痛点”是共通的。学生和老师们的时间都很宝贵但平台设计上难免存在一些需要手动重复点击、信息分散难以汇总的环节。这个工具的核心价值就在于用自动化的思路把这些零碎、耗时的“体力活”交给程序去处理把人解放出来专注于更重要的学习和教学思考本身。它不是什么破解或外挂不涉及任何修改成绩、恶意刷分等违规行为其所有操作都严格模拟正常用户通过浏览器进行的手动操作本质上是一个“浏览器自动化”和“网络请求处理”的实践项目非常适合有一定Python基础想深入理解网页交互、HTTP协议以及自动化测试框架Selenium的同学练手。2. 工具整体设计与技术选型考量当初设计这个工具时首要考虑的是稳定性、可维护性和低侵入性。稳定性意味着工具要能应对网站前端轻微的改版和网络波动可维护性要求代码结构清晰便于后续增加新功能或修改旧逻辑低侵入性则是指工具尽可能不依赖复杂的系统环境或昂贵的第三方服务。2.1 核心架构模拟浏览器 vs. 直接请求这是第一个关键决策点。处理网页交互主要有两种思路模拟浏览器如Selenium, Playwright通过程序控制一个真实的浏览器如Chrome实例执行点击、输入、滚动等操作。这种方式最接近真人操作能完美处理由JavaScript动态渲染的页面内容稳定性高。直接发送HTTP请求如Requests库通过分析网页的网络请求XHR/Fetch直接模拟这些请求来获取数据或提交表单。这种方式效率极高资源占用少但难度也大需要逆向分析网站接口且一旦接口变更脚本就容易失效。对于“雨课堂”这类现代Web应用其页面大量依赖JavaScript动态加载数据登录过程也可能有复杂的验证逻辑。因此我选择了以Selenium模拟浏览器为主辅以Requests库处理已识别的稳定数据接口的混合架构。这样既能保证核心流程登录、导航的可靠性又能在获取静态资源如课件文件链接时提升效率。2.2 主要技术栈与选型理由Selenium ChromeDriver这是自动化操作的基石。Selenium是行业标准社区活跃资料丰富。选择ChromeDriver是因为Chrome浏览器市场占有率最高其开发者工具对分析网页结构极为友好。为什么不选无头模式Headless起步因为在开发调试阶段能看到浏览器的实际操作过程至关重要能直观地定位元素定位失败、页面跳转异常等问题。Requests BeautifulSoup4Requests库用于处理HTTP会话保持登录状态、下载文件以及调用那些已经分析清楚的API。BeautifulSoup4则用于解析静态HTML页面虽然雨课堂动态内容多但部分列表页的基础结构仍可用其快速提取。Pandas这是一个“神器”。用于将爬取到的课程列表、作业信息、成绩记录等结构化数据轻松地整理、清洗并导出为Excel或CSV文件方便后续分析和归档。Schedule / APScheduler用于实现定时任务。比如设定每天上午8点55分自动检查第一节课的签到。考虑到工具的轻量化初期可以直接使用Python内置的time循环但使用轻量级的定时库能让代码更清晰。配置文件如config.ini或config.yaml将用户名、密码、课程ID、定时任务周期等可变参数外置。绝对不要将敏感信息硬编码在脚本里。这是保证代码可分享、可配置的关键。注意整个项目建立在合法合规使用的前提下。工具的设计目的是提升个人学习效率而非进行任何形式的攻击、刷量或干扰平台正常运行。使用时请务必遵守雨课堂的用户协议控制请求频率避免对服务器造成不必要的压力。3. 核心功能模块拆解与实现细节这个工具包通常包含几个独立的脚本每个脚本负责一个相对独立的功能。下面我们来逐一拆解几个典型模块的实现逻辑和注意事项。3.1 模块一自动化登录与会话保持这是所有功能的起点也是最容易出错的环节。实现思路使用Selenium启动浏览器访问雨课堂登录页。定位用户名和密码输入框。这里不能直接用find_element_by_id因为前端框架生成的ID可能是动态的。更稳健的方法是使用find_element(By.XPATH, “//input[placeholder‘手机号/邮箱’]”)或通过CSS选择器定位。输入凭据。这里有一个关键技巧在输入前最好先clear()一下输入框避免残留内容。输入时可以使用send_keys(config[‘username’])并配合短暂的time.sleep(1)或更优的WebDriverWait等待模拟人的操作间隔。点击登录按钮。同样需要等待按钮可点击element_to_be_clickable。登录成功后最关键的一步是获取并保存会话Cookie。使用driver.get_cookies()可以将当前浏览器的登录状态以Cookie列表的形式 dump 下来。将这个列表用json.dump()保存到本地文件。# 示例代码片段保存Cookie from selenium import webdriver import json, time driver webdriver.Chrome() driver.get(“https://www.yuketang.cn/“) # …执行登录操作… time.sleep(5) # 确保登录完全跳转成功 cookies driver.get_cookies() with open(‘cookies.json’, ‘w’) as f: json.dump(cookies, f) driver.quit()后续的Requests操作就可以先加载这个cookies.json文件然后将Cookie添加到会话中这样Requests发起的请求就带上了登录状态无需每次都走Selenium登录。实操心得雨课堂的登录页可能有滑块验证码或短信验证码。对于个人自用工具最简单的处理方式是在首次运行时手动完成一次登录并保存Cookie。这个Cookie通常会有一段较长的有效期如几周在此期间内脚本都可以直接使用。这避免了处理复杂验证码的难题符合“低侵入性”原则。3.2 模块二课程列表与课件批量下载登录后通常需要先获取用户的所有课程列表。实现思路导航到“我的课程”页面。使用Selenium或直接使用带Cookie的Requests访问课程列表API/页面。解析课程信息。分析页面结构通常每个课程卡片会包含课程名称、授课教师、课程ID关键等。使用Selenium的find_elements配合循环提取或用BeautifulSoup解析静态HTML。遍历课程进入每个课程的资源页面。这里课程ID就派上用场了可以构造出类似https://www.yuketang.cn/web/course/{course_id}/resource的URL。定位并遍历课件列表。课件可能是PDF、PPT、视频链接。需要分析这些资源元素的HTML结构提取出真实的文件下载链接。有时下载链接是直接暴露的有时可能需要点击触发一个JavaScript事件然后从浏览器的网络请求日志中捕获真实的文件URL。使用Requests下载文件。获取到真实的文件URL后使用Requests的get方法设置streamTrue以支持大文件流式下载并将内容写入本地文件。务必根据URL中的文件名或Content-Disposition响应头来为文件命名。# 示例代码片段使用Requests下载文件 import requests from urllib.parse import unquote def download_file(url, save_path, cookies): headers { ‘User-Agent’: ‘Mozilla/5.0 …‘ } # 使用会话保持Cookie session requests.Session() for cookie in cookies: session.cookies.set(cookie[‘name’], cookie[‘value’]) response session.get(url, headersheaders, streamTrue) # 尝试从响应头获取文件名 content_disposition response.headers.get(‘Content-Disposition’) if content_disposition: filename unquote(content_disposition.split(‘filename’)[1].strip(‘“‘)) else: filename url.split(‘/’)[-1].split(‘?’)[0] # 从URL截取 full_path os.path.join(save_path, filename) with open(full_path, ‘wb’) as f: for chunk in response.iter_content(chunk_size8192): f.write(chunk) print(f”文件已下载: {full_path}“)注意事项频率控制在循环下载文件时务必在请求之间添加随机延时如time.sleep(random.uniform(1, 3))这是基本的网络礼仪也是对目标服务器的保护。文件去重下载前检查本地是否已存在同名文件可以通过比较文件大小或MD5值来判断内容是否一致避免重复下载。目录组织建议按“学期/课程名/资源类型”的层级创建目录来存放文件便于后期管理。3.3 模块三自动签到与互动任务模拟这是工具中“自动化”色彩最浓的部分需要精确模拟用户点击行为。实现思路监听或轮询。有两种模式一是定时启动脚本检查当前时间是否有课二是在上课期间让脚本在后台以较长间隔如5分钟轮询课程页面。识别签到活动。签到通常表现为页面上的一个按钮、弹窗或特殊标识。需要分析签到活动出现时页面DOM结构的变化。可能是出现一个id为checkin-btn的按钮或者一个包含“签到”文字的div。定位并操作元素。使用WebDriverWait和expected_conditions来等待特定元素出现并变为可点击状态这比固定sleep更可靠。然后执行click()操作。处理可能的验证。有些签到可能有简单的图片验证码或地理位置确认。对于图片验证码自用工具可以考虑接入一个OCR API成本考量或者更实际的做法是设计一个报警机制当脚本检测到无法自动处理的验证时通过邮件、Server酱或Telegram Bot给自己发送一条通知提醒手动操作。# 示例代码片段等待并点击签到按钮 from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By import time def auto_checkin(driver): try: # 等待最多30秒直到签到按钮出现并可点击 checkin_button WebDriverWait(driver, 30).until( EC.element_to_be_clickable((By.XPATH, “//button[contains(text(), ‘签到’)]“)) ) checkin_button.click() print(“[成功] 签到完成”) time.sleep(2) # 检查是否有确认弹窗需要关闭 # … return True except Exception as e: print(f”[失败] 未找到签到按钮或操作失败: {e}“) # 这里可以触发报警通知 return False核心提醒此功能请务必谨慎、合理使用。仅用于处理那些因网络延迟、临时离开等合理原因可能错过的签到且必须确保符合课程规定。自动化不应成为逃避课堂参与的理由。3.4 模块四信息聚合与通知工具不仅可以“取”还可以“理”和“推”。实现思路信息抓取定期运行脚本扫描所有课程的“公告”、“作业”、“成绩”板块。使用Selenium或Requests获取这些页面的HTML。数据解析用BeautifulSoup或直接解析JSON API返回的数据提取公告标题、发布时间、作业截止日期、成绩更新等关键信息。数据聚合与存储使用Pandas的DataFrame来整理这些信息。可以新建一个DataFrame也可以读取之前存储的CSV文件进行比对和更新。变化检测与通知比较新旧数据筛选出新发布的公告、新布置的作业或新公布的成绩。然后通过集成邮件smtplib、微信推送Server酱、Telegram Bot等渠道将变化摘要发送给自己。# 示例代码片段使用Pandas比较数据更新 import pandas as pd def check_new_announcements(old_df_path, new_announcements_list): # new_announcements_list 是从网页解析出的字典列表 new_df pd.DataFrame(new_announcements_list) try: old_df pd.read_csv(old_df_path) # 基于唯一标识如公告ID或标题时间找出新增项 merged old_df.merge(new_df, how‘outer’, indicatorTrue) new_items merged[merged[‘_merge’] ‘right_only’].drop(columns[‘_merge’]) except FileNotFoundError: # 首次运行所有都是新的 new_items new_df if not new_items.empty: print(“发现新公告”) # 发送通知… # 更新本地存储 new_df.to_csv(old_df_path, indexFalse) return new_items这个模块将工具从一个被动的自动化脚本升级为一个主动的信息管家价值大大提升。4. 工程化与可持续性设计一个随手写的脚本和一个可持续使用的工具之间差的就是“工程化”的细节。4.1 配置管理使用config.ini或config.yaml来管理所有配置。# config.ini 示例 [account] username your_student_id password your_password_encrypted_or_plaintext # 强烈建议首次手动登录后使用Cookie而非存储密码 [paths] download_root ./courses_data cookies_file ./cookies.json [notification] email_enabled false email_sender your_emailgmail.com email_password app_specific_password # 使用应用专用密码 email_receiver your_emailgmail.com serverchan_key # Server酱的SCKEY [schedule] check_interval_minutes 15 auto_checkin_enabled true4.2 日志记录使用Python内置的logging模块为程序添加详细的日志。这有助于在无人值守运行时排查问题。import logging logging.basicConfig( levellogging.INFO, format‘%(asctime)s - %(name)s - %(levelname)s - %(message)s’, handlers[ logging.FileHandler(‘assistant.log’), logging.StreamHandler() ] ) logger logging.getLogger(__name__) # 在代码中使用 logger.info(“开始课程列表获取…”) try: # 一些操作 logger.info(“成功获取到%d门课程”, len(courses)) except Exception as e: logger.error(“获取课程列表时发生错误: %s”, e, exc_infoTrue)4.3 错误处理与重试机制网络请求和网页自动化充满不确定性健壮的错误处理必不可少。Try-Except块对所有可能失败的操作网络请求、元素查找、文件IO进行包裹。重试装饰器对于网络请求等瞬态错误可以使用retrying库或自己实现一个简单的重试逻辑。import time from functools import wraps def retry_on_failure(max_retries3, delay2): def decorator(func): wraps(func) def wrapper(*args, **kwargs): last_exception None for attempt in range(max_retries): try: return func(*args, **kwargs) except Exception as e: last_exception e print(f”{func.__name__} 第{attempt1}次尝试失败: {e}“) if attempt max_retries - 1: time.sleep(delay) raise last_exception return wrapper return decorator retry_on_failure(max_retries3, delay5) def fetch_course_page(url, session): response session.get(url, timeout10) response.raise_for_status() return response.text5. 常见问题、排查技巧与伦理思考在实际开发和运行过程中你肯定会遇到各种各样的问题。下面是一些典型场景和解决思路。5.1 元素定位失败这是Selenium自动化中最常见的问题。可能原因1页面未加载完成。解决方案使用WebDriverWait配合expected_conditions如presence_of_element_located,visibility_of_element_located,element_to_be_clickable代替固定的time.sleep。可能原因2元素在iframe或shadow DOM内。解决方案需要先使用driver.switch_to.frame(frame_reference)切换到对应的iframe或使用JavaScript穿透shadow DOM。可能原因3元素属性是动态生成的。解决方案避免使用绝对路径的XPath或依赖id如果id是动态的。尝试使用更稳定的相对定位方式如通过文本内容、CSS类组合或数据属性style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;" />
返回列表