实战解析:如何高效爬取长江雨课堂选择题并构建本地习题库

实战解析:如何高效爬取长江雨课堂选择题并构建本地习题库 1. 项目背景与需求分析每次期末考试前最让人头疼的就是整理复习资料。去年我在使用长江雨课堂时发现老师布置的练习题散落在不同章节复习时需要反复跳转页面效率极低。于是萌生了一个想法能不能把这些题目自动收集起来建立本地习题库这个需求看似简单但实际操作涉及多个技术环节登录认证需要模拟浏览器行为携带Cookie数据定位从复杂的JSON结构中精准提取题目信息异常处理区分选择题和填空题的数据结构差异数据存储设计合理的MySQL表结构我花了两个周末时间最终实现了这个自动化系统。下面就把整个开发过程拆解成可复用的技术方案特别适合有Python基础但刚接触爬虫的同学。2. 环境准备与工具选型2.1 基础环境配置建议使用Python 3.8版本太新的版本可能会遇到库兼容问题。我的开发环境配置如下pip install requests2.26.0 pip install lxml4.6.3 pip install pymysql1.0.2为什么选择这些版本实测发现requests 2.26.0在处理长连接时最稳定lxml 4.6.3的XPath解析成功率最高pymysql 1.0.2与MySQL 8.0兼容性最好2.2 浏览器调试工具使用技巧按F12打开开发者工具后重点看这两个面板Network面板勾选Preserve log防止页面跳转丢失请求记录Elements面板使用CtrlF搜索题目关键词定位DOM节点一个小技巧在请求头复制Cookie时建议用Copy as cURL功能然后到https://curlconverter.com/网站转换成Python代码比手动复制更可靠。3. 爬虫核心实现3.1 登录认证机制长江雨课堂采用Cookie验证获取方式分三步正常登录网页版打开任意课程页面在Network标签找到detlist接口请求关键代码实现headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64), Cookie: your_cookie_here # 建议定期更新 }注意Cookie有效期通常为7天建议写个自动检测机制。我后来改进的方案是当收到403响应时自动弹出浏览器窗口要求重新登录。3.2 数据结构解析API返回的JSON结构非常复杂主要数据路径如下data → problem_results → slide → ProblemBodys[0] → Paragraphs[0] → Lines[0] → Html (题目) Problem → Bullets[] → Contents[] (选项)解析时的几个坑列表索引可能越界建议先判断长度Html字段包含XML格式数据需要用XPath二次解析填空题没有Bullets字段直接访问会报KeyError改进后的健壮性代码try: question_html i[slide][ProblemBodys][0][Paragraphs][0][Lines][0][Html] question etree.HTML(question_html).xpath(//span/text())[0] except (IndexError, KeyError): continue # 跳过异常题目4. 数据存储方案4.1 数据库设计经过多次迭代我最终采用的表结构如下CREATE TABLE question_bank ( id INT NOT NULL AUTO_INCREMENT, question VARCHAR(255) NOT NULL COMMENT 题目内容, question_type ENUM(choice,fill) NOT NULL COMMENT 题型, options TEXT COMMENT 选项JSON格式, answer VARCHAR(50) NOT NULL, course_id VARCHAR(20) NOT NULL COMMENT 关联课程, create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY idx_question (question(100)) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4这个设计的优势使用utf8mb4编码支持emoji等特殊字符增加题型字段方便后续扩展选项存储为JSON格式更灵活4.2 批量插入优化直接循环执行INSERT效率太低我改用executemany批量操作data [(q1,ans1,opt1), (q2,ans2,opt2)] cursor.executemany( INSERT INTO question_bank VALUES (%s,%s,%s), data ) db.commit()实测1万条记录的插入时间从3分钟降到5秒性能提升36倍。5. 异常处理与调试5.1 常见错误排查Cookie失效表现为返回403状态码解决方案实现自动刷新机制JSON解析错误通常是API返回非JSON数据try: data response.json() except ValueError: print(Invalid JSON:, response.text[:200])XPath匹配失败HTML结构可能有变建议先用浏览器验证XPath有效性5.2 日志记录方案添加日志功能能极大提升调试效率import logging logging.basicConfig( filenamespider.log, levellogging.INFO, format%(asctime)s - %(levelname)s: %(message)s )记录关键操作logging.info(f成功抓取{len(questions)}道题目) logging.warning(f跳过异常题目: {traceback.format_exc()})6. 项目扩展思路6.1 定时自动同步用APScheduler实现每天凌晨自动同步from apscheduler.schedulers.blocking import BlockingScheduler sched BlockingScheduler() sched.scheduled_job(cron, hour2) def auto_sync(): # 执行爬虫逻辑 sched.start()6.2 可视化查询界面用Flask快速搭建Web界面from flask import Flask app Flask(__name__) app.route(/questions) def list_questions(): # 查询数据库返回JSON6.3 移动端适配将数据导出为Anki记忆卡格式利用间隔重复算法提升记忆效率。这个项目从最初的简单爬虫逐步发展成完整的习题管理系统。最大的收获不是技术本身而是学会如何把一个实际需求拆解成可执行的技术方案。过程中遇到的每个报错都是最好的学习机会现在回头看最初的代码发现至少有10处可以优化的地方。