手把手教你用Python requests和schedule模块,搞定选课系统自动抢课(附完整代码)
·
Python自动化选课实战:从请求构造到定时任务的全流程解析
每到选课季,校园服务器总是被挤得水泄不通。那些热门课程往往在开放后的几秒内就被一抢而空,手动刷新页面根本来不及反应。作为一名Python爱好者,我发现用requests和schedule模块可以构建一个高效的自动化解决方案,不仅能精准把握选课时机,还能避免重复机械操作。下面我将完整展示如何从零搭建这样一个系统,并解释每个技术环节的设计考量。
1. 环境准备与基础概念
在开始编码前,我们需要明确几个关键技术点。现代选课系统通常采用Cookie+CSRF Token的双重验证机制,这是我们需要突破的第一道关卡。
必备工具安装:
pip install requests schedule
为什么选择这两个库? requests是Python中最流行的HTTP客户端库,而schedule则提供了直观的定时任务接口。它们的组合足以应对大多数自动化场景。
关键概念解析:
- Cookie:服务器用来识别客户端身份的字符串,通常包含登录状态等信息
- CSRF Token:跨站请求伪造防护令牌,每次会话都会变化
- 请求头(Headers):告诉服务器客户端的环境信息,如浏览器类型、接受的内容格式等
提示:实际操作前建议先在浏览器开发者工具(F12)的Network选项卡观察正常选课流程的请求细节
2. 身份认证与CSRF防护突破
获取有效的会话是自动化的第一步。以下代码展示了如何从浏览器提取Cookie并获取CSRF Token:
import requests
import re
def get_csrf_token(cookies):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36...',
'Referer': 'http://your-school.edu/xkapp/'
}
response = requests.get(
'http://your-school.edu/xkapp/home.do',
cookies=cookies,
headers=headers,
verify=False # 仅用于测试环境,生产环境应配置正确证书
)
token = re.search(r'csrfToken\s*=\s*"([a-f0-9]+)"', response.text).group(1)
return token
Cookie获取实操步骤:
- 正常登录选课系统
- 打开开发者工具(F12)切换到Network选项卡
- 刷新页面,查看任意请求的Headers部分
- 复制Cookie字符串并转换为Python字典格式
常见问题排查:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 403禁止访问 | Cookie过期 | 重新登录获取最新Cookie |
| Token无效 | 页面未正确加载 | 检查Referer和User-Agent是否匹配浏览器 |
| 连接超时 | 服务器限制 | 添加适当的请求间隔 |
3. 选课请求的精细构造
有了身份凭证后,我们需要精确构造选课请求。关键是要分析正常选课时的请求参数:
def submit_course_request(course_code, csrf_token, cookies):
timestamp = int(time.time() * 1000) # 13位时间戳
data = {
'bjdm': course_code,
'lx': '7', # 课程类型代码
'bqmc': '专业选修',
'csrfToken': csrf_token
}
params = {'_': timestamp}
response = requests.post(
'http://your-school.edu/xkapp/select.do',
params=params,
data=data,
cookies=cookies,
headers={'X-Requested-With': 'XMLHttpRequest'}
)
return response.json()
课程代码获取方法:
- 在选课界面打开开发者工具
- 切换到目标课程分类
- 查找类似
loadCourseList.do的XHR请求 - 在响应数据中定位目标课程的bjdm字段
注意:不同学校系统的参数名称可能略有差异,需要根据实际情况调整
4. 定时任务与执行策略
schedule模块让定时执行变得非常简单,但需要考虑一些优化策略:
import schedule
import time
import random
def job():
try:
cookies = get_cookies_from_file() # 从文件读取最新Cookie
token = get_csrf_token(cookies)
result = submit_course_request('COURSE123', token, cookies)
log_result(result)
except Exception as e:
log_error(e)
# 基础定时配置
schedule.every().day.at("12:59:50").do(job) # 提前10秒启动
schedule.every(5).seconds.do(job) # 持续尝试
while True:
schedule.run_pending()
time.sleep(1 + random.random()) # 添加随机延迟避免封禁
高级优化技巧:
- 多课程优先级:使用优先队列管理多个目标课程
- 智能重试:根据响应状态动态调整请求频率
- 分布式部署:在不同网络环境运行多个实例
- 异常处理:网络波动、验证码等情况的应对策略
性能对比表:
| 策略 | 成功率 | 服务器压力 | 实现复杂度 |
|---|---|---|---|
| 单次定时 | 中等 | 低 | 简单 |
| 循环尝试 | 高 | 中 | 中等 |
| 分布式 | 极高 | 高 | 复杂 |
5. 工程化与扩展思路
将脚本升级为完整应用需要考虑更多生产环境因素:
# 配置管理示例
import configparser
import logging
def init_config():
config = configparser.ConfigParser()
config.read('config.ini')
return config
def setup_logging():
logging.basicConfig(
filename='course_select.log',
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
# 主程序结构
def main():
setup_logging()
config = init_config()
while True:
run_selection_cycle(config)
time.sleep(config.getint('DEFAULT', 'interval'))
扩展功能方向:
- GUI界面:使用PyQt或Tkinter构建用户界面
- 消息通知:集成邮件/短信通知功能
- 负载均衡:多课程同时监控
- 历史数据分析:选课成功率统计
安全注意事项:
- 不要公开分享包含个人Cookie的代码
- 遵守学校网络使用政策
- 控制请求频率避免给服务器造成过大压力
- 重要操作前建议先进行本地测试
更多推荐


所有评论(0)