XJTU全校课表的爬虫demo
'# XJTU全校课表的爬虫demo
一、背景与问题
西安交通大学(XJTU)的全校课表系统是典型的Web应用,其核心功能包括学生查询个人课表、教师查询教学安排、管理员维护课程信息等。作为一个典型的B/S架构系统,其数据存储通常采用MySQL/PostgreSQL等关系型数据库,前端通过Spring Boot、Django等框架渲染页面。
在实际开发中,我们常遇到以下问题:
- 教务系统数据接口不开放,无法直接调用API
- 课表数据需要用户登录后才能查看
- 页面内容存在JavaScript动态渲染
- 存在反爬虫机制(如验证码、请求频率限制)
本篇文章将深入分析XJTU课表系统的爬虫实现方案,重点探讨如何在不违反服务条款的前提下,通过合法途径获取数据。
二、基本原理
XJTU课表系统的核心数据存储结构通常包含以下表:
courses(课程信息):包含课程编号、名称、学分、上课时间等teachers(教师信息):包含教师工号、姓名、所属学院schedule(课表安排):关联课程、教室、时间、教师等users(用户信息):包含学号、姓名、所属院系
数据访问流程如下:
- 用户通过浏览器访问
https://xjtu.edu.cn/course路径 - 前端发送AJAX请求到
/api/schedule接口 - 后端从数据库查询数据并返回JSON格式
- 前端通过JavaScript渲染课表表格
三、环境准备
# 安装Python依赖
pip install requests beautifulsoup4 lxml selenium四、核心实现
1. 网站分析与请求模拟
import requests
from bs4 import BeautifulSoup
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4443.114 Safari/537.36'
}
# 获取登录页面
login_url = 'https://xjtu.edu.cn/login'
response = requests.get(login_url, headers=headers)
soup = BeautifulSoup(response.text, 'lxml')
# 分析登录参数(假设存在hidden字段)
csrf_token = soup.find('input', {'name': 'csrf_token'})['value']关键代码解释:
- 使用
User-Agent模拟浏览器访问 - 通过BeautifulSoup解析HTML,提取隐藏字段
- 注意处理可能存在的CSRF令牌验证
2. 登录与会话管理
login_data = {
'username': 'your_username',
'password': 'your_password',
'csrf_token': csrf_token
}
# 创建会话对象
session = requests.Session()
session.post(login_url, headers=headers, data=login_data)关键代码解释:
- 使用
requests.Session()保持会话状态 - 需要处理可能的验证码验证(如使用第三方OCR服务)
3. 课表数据爬取
schedule_url = 'https://xjtu.edu.cn/api/schedule'
response = session.get(schedule_url, headers=headers)
data = response.json()
# 解析课表数据
for course in data['courses']:
print(f"课程名称: {course['name']}, 时间: {course['time']}, 教室: {course['room']}")关键代码解释:
- 直接调用API接口获取JSON数据
- 需要处理可能的分页参数(如
page=1、page=2)
五、完整案例
1. 完整爬虫脚本(带异常处理)
import requests
from bs4 import BeautifulSoup
import json
import time
import logging
# 配置日志
logging.basicConfig(level=logging.INFO)
def get_csrf_token():
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4443.114 Safari/537.36'
}
login_url = 'https://xjtu.edu.cn/login'
response = requests.get(login_url, headers=headers)
soup = BeautifulSoup(response.text, 'lxml')
return soup.find('input', {'name': 'csrf_token'})['value']
def login(username, password):
csrf_token = get_csrf_token()
login_data = {
'username': username,
'password': password,
'csrf_token': csrf_token
}
session = requests.Session()
session.post('https://xjtu.edu.cn/login', data=login_data)
return session
def fetch_schedule(session):
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4443.114 Safari/537.36'
}
schedule_url = 'https://xjtu.edu.cn/api/schedule'
try:
response = session.get(schedule_url, headers=headers)
response.raise_for_status()
return response.json()
except Exception as e:
logging.error(f"请求失败: {str(e)}")
return None
if __name__ == '__main__':
session = login('your_username', 'your_password')
if session:
schedule_data = fetch_schedule(session)
if schedule_data:
print(json.dumps(schedule_data, indent=2))关键代码解释:
- 使用
try-except块处理网络异常 - 模拟登录流程后获取会话对象
- 处理可能的API限流(添加
time.sleep(1))
六、源码解析
1. 请求头构造
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4443.114 Safari/537.36'
}关键点:
- 必须使用符合标准的User-Agent
- 部分网站会检测UA字段,使用
Chrome/Firefox等浏览器UA更易通过验证
2. 响应处理
response = session.get(schedule_url, headers=headers)
response.raise_for_status()关键点:
raise_for_status()会检查HTTP状态码,4xx/5xx会抛出异常- 需要处理可能的重定向(如
allow_redirects=True)
七、进阶使用
1. 爬虫调度器
from datetime import datetime
def schedule_crawler(username, password, interval=3600):
while True:
try:
session = login(username, password)
if session:
schedule_data = fetch_schedule(session)
if schedule_data:
print(f"{datetime.now()}: 爬虫任务完成")
else:
print("未获取到课表数据")
time.sleep(interval)
except Exception as e:
print(f"发生异常: {str(e)}")
time.sleep(60)关键点:
- 使用定时任务定期获取数据
- 需要处理可能的登录失效问题(如会话过期)
2. 数据持久化
import sqlite3
def save_to_sqlite(data):
conn = sqlite3.connect('schedule.db')
c = conn.cursor()
c.execute('CREATE TABLE IF NOT EXISTS schedule (id INTEGER PRIMARY KEY, course TEXT, time TEXT, room TEXT)')
for item in data['courses']:
c.execute("INSERT INTO schedule (course, time, room) VALUES (?, ?, ?)",
(item['name'], item['time'], item['room']))
conn.commit()
conn.close()关键点:
- 使用SQLite存储数据(可扩展为MySQL/PostgreSQL)
- 注意处理SQL注入问题(使用参数化查询)
八、性能与工程实践
1. 性能优化方案
| 优化措施 | 说明 |
|---|---|
| 并发请求 | 使用concurrent.futures.ThreadPoolExecutor |
| 缓存机制 | 使用requests_cache库缓存响应 |
| 资源复用 | 使用requests.Session()保持连接 |
| 限流控制 | 设置合理的请求间隔(如1秒) |
2. 异常处理策略
def safe_request(url, headers, max_retries=3):
for i in range(max_retries):
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
logging.warning(f"第{i+1}次请求失败: {str(e)}")
time.sleep(2 ** i)
return None关键点:
- 处理网络波动和服务器故障
- 使用指数退避算法重试
3. 安全风险分析
| 风险类型 | 防范措施 |
|---|---|
| 验证码识别 | 使用第三方OCR服务(如百度AI) |
| IP封禁 | 使用代理IP池 |
| 请求频率限制 | 设置合理的请求间隔 |
| 数据泄露 | 对敏感数据进行加密处理 |
九、常见问题与踩坑
1. 常见错误及解决方案
| 错误类型 | 错误示例 | 解决方案 |
|---|---|---|
| 403 Forbidden | requests.get()返回403 | 检查User-Agent,添加Referer头 |
| 500 Internal Server Error | 服务器端错误 | 检查API接口是否变更 |
| JSON解析错误 | json.loads()报错 | 检查响应内容是否为JSON格式 |
| 验证码识别失败 | 验证码识别错误 | 使用第三方识别服务 |
2. 反爬虫机制应对
# 添加Referer头
headers = {
'User-Agent': 'Mozilla/5.0',
'Referer': 'https://xjtu.edu.cn/course'
}关键点:
- 部分网站要求
Referer头 - 需要分析目标网站的请求头特征
十、最佳实践
- 数据存储:建议使用关系型数据库存储课表数据,便于后续查询和分析
- 异常处理:每个请求都应该包含重试机制和异常捕获
- 日志记录:详细记录请求和响应内容,便于排查问题
- 配置管理:将敏感信息(如用户名密码)存储在配置文件中,避免硬编码
- 合规性:遵守《中华人民共和国计算机信息系统安全保护条例》,不用于非法用途
十一、总结
XJTU课表系统的爬虫实现涉及多个技术点:
- 网络请求与会话管理
- HTML解析与JSON数据处理
- 异常处理与性能优化
- 安全风险防控
本篇文章通过完整案例展示了如何在不违反服务条款的前提下,通过合法途径获取课表数据。需要注意的是,爬虫技术应遵守相关法律法规,不得用于非法用途。在实际开发中,建议优先考虑官方API接口,只有在必要时才使用爬虫技术。
对于需要处理大量数据或复杂业务场景的项目,可以考虑以下扩展方向:
- 使用Scrapy框架构建分布式爬虫
- 集成数据库事务处理保证数据一致性
- 添加数据校验逻辑确保数据质量
- 实现可视化界面供用户查询课表数据
通过本篇文章的深入探讨,我们不仅掌握了XJTU课表系统的爬虫实现方法,更重要的是理解了爬虫技术的使用边界和工程实践要点。在实际开发中,需要根据具体需求选择最合适的解决方案。
评论已关闭