Python+Selenium+ddddocr实现校园讲座全自动预约脚本
2026/9/15 22:30:26 网站建设 项目流程

简介:本资源是一套面向东南大学在校学生及Python自动化初学者的讲座抢票实战工具,专为解决人文与科学素养系列讲座预约中验证码识别难、短信认证繁琐、跨校区优先级混乱等高频痛点而设计。脚本基于Python+Selenium构建,集成ddddocr实现图形验证码自动识别,并嵌入手机短信双因素认证处理逻辑,支持按用户所属校区智能匹配并优先抢票,显著提升成功率与操作效率。压缩包共1045个文件,主体为1037张验证码训练样本(jpg)、3个核心功能脚本(py)、2个配置说明文本(txt)及1份使用文档(docx),总大小仅955KB,结构紧凑、即下即用。目前已有51人学习下载,读者可直接复用完整可运行脚本,获得含验证码样本集、多校区调度逻辑、短信验证码自动提取与填入等关键能力的端到端解决方案,兼具教学参考性与工程实用性。

1. 项目缘起:当“手速”成为稀缺资源

在高校里,尤其是像东南大学这样拥有深厚人文与科学底蕴的学府,那些由名家主讲的“人文与科学素养系列讲座”往往是一座难求。我至今还记得,为了听一场心仪已久的讲座,提前半小时守在电脑前,不断刷新预约页面,与全校数千名同学比拼“手速”和网速的紧张感。页面卡顿、验证码加载失败、提交按钮转圈……这些场景对于经历过“抢票”的同学来说,再熟悉不过了。最终,往往是页面显示“名额已满”,留下满屏的遗憾。这种纯粹依赖人工操作的“抢票”模式,效率低下且极不公平,它考验的已经不是你对知识的渴望,而是你的网络环境和反应速度。

作为一名计算机相关专业的学生,同时也是Python和自动化技术的爱好者,我自然而然地想到:能否用技术手段来解决这个痛点?让程序代替人工,去完成那些重复、机械的刷新、识别和点击操作,从而将宝贵的精力留给讲座内容本身。这个想法催生了本项目的核心:一个专为东南大学讲座预约系统设计的全自动智能预约脚本。它不仅仅是一个简单的“点击器”,而是一个集成了Web自动化、图形验证码智能识别以及双因素认证处理的综合工具。我的目标很明确——打造一个稳定、高效、智能的“数字助手”,帮助真正想听讲座的同学跨越技术门槛,公平地获取学习资源。

2. 技术栈选型与核心组件拆解

要实现一个健壮的自动化脚本,技术选型是第一步。这就像盖房子前选建材,每一块都决定了最终的稳固性和实用性。经过多轮对比和实际测试,我最终确定了以Python为核心,Selenium为骨架,ddddocr为“眼睛”,并辅以一系列辅助库的技术方案。

### 2.1 为什么是Python + Selenium?

Python作为脚本语言的王者,其语法简洁、库生态丰富,是快速开发原型和自动化任务的不二之选。而Selenium则是Web自动化的“瑞士军刀”。它支持几乎所有主流浏览器(Chrome, Firefox, Edge等),能够模拟真实用户的所有操作:打开网页、点击按钮、输入文本、下拉选择等。更重要的是,Selenium WebDriver协议是W3C标准,这意味着其行为与真实浏览器高度一致,极大地降低了被简单反爬策略(如检测navigator.webdriver属性)识别的风险。相比于Requests库直接发包,Selenium模拟的是“真人”在操作浏览器,对于需要处理JavaScript动态加载、复杂交互逻辑的校园网站来说,这是更可靠的选择。

### 2.2 图形验证码识别:ddddocr的降维打击

校园预约系统为了防止恶意刷票,图形验证码是标配。传统的验证码识别方案,如Tesseract OCR,对于字符清晰、背景简单的验证码尚可一战,但面对国内网站常见的扭曲、粘连、干扰线验证码,其识别率往往惨不忍睹。手动打码平台又存在速度、成本和稳定性的问题。

ddddocr的出现,堪称“降维打击”。这是一个基于深度学习的OCR开源库,专门针对中文验证码进行了优化。它的强大之处在于:

  1. 高准确率:对于常见的数字、英文、中文混合验证码,识别率远超传统OCR,实测在目标网站上的识别成功率可达95%以上。
  2. 零依赖与易用性:纯Python编写,通过pip install ddddocr即可安装,无需配置复杂的深度学习环境(如TensorFlow/PyTorch)。其API极其简单,通常两三行代码就能完成验证码图片的识别。
  3. 轻量高效:模型经过高度优化,识别速度极快,通常在几十到几百毫秒内完成,完全满足抢票场景下对实时性的苛刻要求。

在项目中,我们将Selenium截取的验证码图片,直接送入ddddocr进行识别,再将识别结果自动填入网页输入框,实现了验证码环节的全自动化。

### 2.3 双因素认证(2FA)处理:模拟人工的短信确认

为了进一步提升安全性,系统在最终提交预约前,可能会触发手机短信验证码环节。这是双因素认证,也是自动化流程中必须跨越的“最后一公里”。这里的核心思路是“模拟人工查看短信并输入”

我们无法(也不应该)直接破解短信网关。因此,方案是:

  1. 信息获取:脚本在运行前,需要用户预先配置好接收短信的手机号(通常就是登录账号绑定的手机号)。
  2. 流程衔接:当Selenium自动化操作触发短信发送后,脚本会进入一个等待循环。
  3. 外部联动(关键):这里需要一个“桥梁”来获取短信内容。一种可行的方案是,在另一台始终登录着电脑版微信或特定监控软件的设备/进程中,通过监听通知或访问特定API(例如,一些手机助手软件提供的本地HTTP接口)来提取新收到的短信验证码。请注意,此操作必须基于用户授权,且仅用于处理发送给用户本人手机的验证码,绝对禁止用于获取他人信息。
  4. 填入提交:脚本获取到短信验证码后,将其填入网页对应输入框,并完成最终提交。

这个过程模拟了用户“拿起手机看短信-回电脑输入”的行为,实现了闭环自动化。

### 2.4 校区优先级调度逻辑

东南大学有多个校区,讲座资源可能按校区分配。一个智能脚本不能盲目抢票,必须理解用户的偏好。因此,我设计了“校区优先级”逻辑。用户可以在配置文件中预设一个校区顺序列表,例如[“九龙湖校区”, “四牌楼校区”, “丁家桥校区”]。脚本在运行时,会按照这个优先级顺序去查找和尝试预约。如果最高优先级的校区名额已满,则自动、无缝地切换到次优先级校区进行尝试,直到成功或所有选项尝试完毕。这大大提升了预约的成功率和用户体验。

3. 系统架构与核心工作流程

理解了核心组件后,我们来看它们是如何协同工作的。整个脚本的运行遵循一个清晰的状态机流程,下图展示了其核心工作流与关键决策点:

flowchart TD A[开始: 初始化配置<br>(账号、密码、优先级)] --> B{登录与验证码识别}; B -- 登录成功 --> C[监控讲座发布页面]; B -- 失败 --> E[记录错误并等待重试]; C --> D{目标讲座出现?}; D -- 是 --> F[进入预约流程]; D -- 否 --> C; F --> G{选择最高优先级校区}; G -- 有名额 --> H[提交预约,触发短信验证]; G -- 无名额 --> I{仍有次优先级校区?}; I -- 是 --> J[切换至下一优先级校区]; I -- 否 --> K[本轮预约失败,结束]; J --> G; H --> L[获取并填入短信验证码]; L --> M{最终提交成功?}; M -- 是 --> N[预约成功,通知用户]; M -- 失败 --> O[流程结束,记录日志];

这个流程图清晰地揭示了脚本的智能之处:它并非简单的线性执行,而是包含了状态判断(登录成功否?)、循环监控(讲座发布否?)、条件分支(校区有无名额?)和异常处理(失败重试)等一系列逻辑。下面,我们拆解几个关键环节的实现细节。

### 3.1 环境搭建与依赖安装

工欲善其事,必先利其器。首先需要搭建Python环境。建议使用Python 3.7及以上版本。通过pip一次性安装所有依赖:

pip install selenium ddddocr requests

接下来是浏览器驱动。以最常用的Chrome为例,你需要下载与本地Chrome浏览器版本匹配的chromedriver,并将其所在目录添加到系统PATH环境变量中,或者将驱动文件直接放在项目目录下。这是Selenium能够控制浏览器的关键。

### 3.2 Selenium自动化核心:模拟真人操作

使用Selenium时,最大的挑战是如何让程序行为更像人,以及如何稳定地定位网页元素。我的经验是:

  1. 使用显式等待(WebDriverWait):绝对避免使用time.sleep()进行固定时长等待。网页加载速度不确定,固定等待要么浪费时间,要么导致元素未加载就操作而报错。显式等待会持续检测某个条件(如元素出现、可点击),条件满足立即继续,并可以设置超时时间。

    from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By # 等待登录按钮出现并可点击,最多等10秒 login_button = WebDriverWait(driver, 10).until( EC.element_to_be_clickable((By.ID, "loginBtn")) ) login_button.click()
  2. 多样化的元素定位策略:不要只依赖一种定位方式(如ID)。优先级通常是:ID > Name > CSS Selector > XPath。CSS Selector通常性能更好,XPath功能强大但可能随页面结构微调而失效。在开发者工具中多练习,找到最稳定、唯一的定位方式。

    # 多种定位方式示例 element_by_id = driver.find_element(By.ID, "username") element_by_css = driver.find_element(By.CSS_SELECTOR, "input.form-control[type='text']") element_by_xpath = driver.find_element(By.XPATH, "//div[@class='lecture-list']//li[1]//a")
  3. 人性化操作模拟:在关键动作间加入随机延时,模拟人的思考间隔;使用ActionChains进行复杂的鼠标移动、悬停操作,而不是直接click()

### 3.3 ddddocr集成:让脚本拥有“眼睛”

验证码识别环节的集成非常简洁。核心步骤如下:

  1. 截取验证码图片:首先需要定位到验证码图片元素,然后将其截图保存。这里要注意,有些网站的验证码是Canvas绘制的,可能需要特殊的JS脚本来获取图片数据。

    from selenium.webdriver.common.by import By import ddddocr # 定位验证码图片元素 captcha_element = driver.find_element(By.ID, "captcha_img") # 截图并保存 captcha_element.screenshot('captcha.png')
  2. 调用ddddocr识别:读取截图文件,调用ddddocr进行识别。

    ocr = ddddocr.DdddOcr() # 创建识别器实例 with open('captcha.png', 'rb') as f: img_bytes = f.read() captcha_text = ocr.classification(img_bytes) # 识别结果 print(f"识别出的验证码是: {captcha_text}")
  3. 填入识别结果:将识别出的文本填入对应的输入框。

    captcha_input = driver.find_element(By.ID, "captcha") captcha_input.clear() captcha_input.send_keys(captcha_text)

注意:验证码识别不可能100%准确。一个健壮的脚本必须包含识别失败的重试机制。例如,识别后提交,如果系统提示验证码错误,则脚本应自动刷新验证码图片,重新截取并识别,循环数次直到成功或达到最大重试次数。

### 3.4 短信验证码处理:实现闭环的关键

这是自动化流程中最需要巧妙设计的一环。如前所述,核心是建立一个外部通道来获取短信。这里以“通过电脑版微信的文件传输助手获取手机通知”为例,描述一种需要用户配合的实现思路:

  1. 用户端准备:用户需要在手机和电脑上同时登录微信,并确保手机的“新消息通知”在电脑端是弹出的。
  2. 脚本端监控(模拟):脚本无法直接读取微信,但可以监控电脑的特定位置。一种“土方法”是,用户将手机短信转发到“文件传输助手”,脚本通过监控电脑上微信窗口的标题变化或使用UI自动化工具(如pyautogui)在特定区域截图并进行OCR,来提取验证码。这种方法极不稳定且依赖特定环境,不推荐用于生产。
  3. 更优方案:使用官方或稳定的第三方短信同步服务。例如,一些手机厂商(如小米、华为)提供了“短信同步到PC”的功能,并可能有开放的本地API。或者,使用一些开源的家庭自动化平台(如Home Assistant)配合特定插件,在收到短信后触发一个Webhook,脚本监听这个Webhook来获取验证码。这些方案都需要用户自行研究搭建,并严格注意隐私安全。

在项目中,我将这部分设计为可插拔的模块。脚本会等待并调用一个名为get_sms_code()的函数,这个函数的实现由用户根据自身情况来编写。我可以提供一个基于简单HTTP服务器或读取本地文件的示例,真正的集成需要用户完成。

def get_sms_code(timeout=120): """ 用户需要根据自身环境实现此函数。 示例:监控一个本地文件,当短信转发到电脑时,另一个程序将验证码写入该文件。 """ # 示例:从本地文件读取 import time start_time = time.time() while time.time() - start_time < timeout: try: with open('sms_code.txt', 'r') as f: code = f.read().strip() if code and len(code) == 6 and code.isdigit(): # 假设是6位数字 # 读取后清空文件,避免下次误用 open('sms_code.txt', 'w').close() return code except FileNotFoundError: pass time.sleep(2) # 每2秒检查一次 raise TimeoutError("等待短信验证码超时")

4. 实战部署与优化策略

有了核心代码,如何让它稳定、隐蔽、高效地运行起来,是另一个维度的挑战。

### 4.1 配置管理与错误处理

一个成熟的脚本不应该把账号密码等敏感信息硬编码在代码里。我使用配置文件(如config.iniconfig.yaml)来管理所有可变参数:

[account] username = your_student_id password = your_password phone = your_phone_number [preference] campus_priority = 九龙湖校区, 四牌楼校区, 丁家桥校区 target_lecture_keywords = 人工智能, 哲学, 艺术 [settings] headless = False # 是否使用无头模式(不显示浏览器界面) max_retry_captcha = 3 sms_wait_timeout = 120

错误处理是脚本健壮性的生命线。必须对每一个可能失败的环节进行捕获和记录:

  • 网络超时或断开
  • 元素定位失败
  • 验证码识别错误
  • 短信验证码获取超时
  • 预约名额已满

脚本应记录详细的日志,包括时间、操作步骤、成功或失败信息、错误追踪等,便于事后排查。

### 4.2 反反爬策略与道德考量

使用自动化脚本必须谨慎,并遵守网站规则。我们的目的是为了学习便利,而非攻击或占用过多公共资源。因此,需要采取一些措施让脚本行为更“友好”:

  1. 降低请求频率:在监控讲座发布时,设置合理的间隔时间(如30-60秒),避免高频请求对服务器造成压力。
  2. 模拟人类行为:除了随机延时,还可以模拟鼠标移动轨迹,在输入时加入随机按键间隔。
  3. 使用真实浏览器环境:Selenium可以通过options参数来隐藏自动化特征,但这不是万能的。最根本的是控制脚本的使用频率和目的。
  4. 最重要的道德约束绝对禁止使用脚本进行恶意刷票、囤积门票然后转卖等行为。脚本应仅用于为自己或少数有真实需求的朋友预约。滥用技术不仅违背初衷,也可能违反校规甚至相关法律法规。

### 4.3 部署与定时运行

脚本开发完成后,可以部署在个人电脑或云服务器上。

  • 个人电脑:可以使用系统自带的定时任务(如Windows的任务计划程序、Linux/Mac的cron)在讲座预约开始前启动脚本。
  • 云服务器:优点是24小时在线,网络稳定。但需要注意云服务器的IP地址是否被校园网系统允许访问(有些系统可能限制了校外IP)。部署时,务必使用无头模式(headless=True)以节省资源。

在服务器上运行,还需要解决无图形界面的问题。对于Chrome,可以安装xvfb(一个虚拟显示服务器)来模拟显示环境。

from selenium import webdriver from selenium.webdriver.chrome.options import Options chrome_options = Options() chrome_options.add_argument('--headless') # 无头模式 chrome_options.add_argument('--no-sandbox') # 在服务器环境下常用参数 chrome_options.add_argument('--disable-dev-shm-usage') # 解决共享内存问题 driver = webdriver.Chrome(options=chrome_options)

5. 常见问题排查与经验心得

在开发和运行这个脚本的过程中,我踩过不少坑,也积累了一些宝贵的经验。

### 5.1 元素定位突然失效?可能是页面结构变了

这是最常见的问题。今天还能运行的脚本,明天可能就因为网站前端的一次小更新而报错“Unable to locate element”。应对策略:

  • 使用相对稳定、语义化的选择器:优先选择具有明确id或唯一name的元素。如果都没有,尝试使用包含元素文本内容的XPath,但也要注意文本可能变化。
  • 实现“元素定位器池”:为同一个元素准备多个备选的定位策略(如ID、CSS、XPath各一个)。在主要定位器失败时,脚本可以自动尝试备选方案。
  • 定期维护:意识到脚本不是一劳永逸的。在重要预约开始前,最好提前运行测试一下核心流程。

### 5.2 验证码识别率下降怎么办?

ddddocr虽然强大,但并非万能。如果发现针对特定网站的验证码识别率下降:

  1. 图片预处理:在将图片送给ddddocr之前,可以先进行一些简单的图像处理,如灰度化、二值化、降噪等。OpenCV库是这方面的好帮手。
    import cv2 image = cv2.imread('captcha.png', cv2.IMREAD_GRAYSCALE) # 灰度化 _, image = cv2.threshold(image, 150, 255, cv2.THRESH_BINARY) # 二值化 cv2.imwrite('captcha_processed.png', image) # 然后用处理后的图片进行识别
  2. 模型微调(进阶):如果验证码风格非常独特且固定,可以考虑收集一批该网站的验证码图片和正确标签,使用ddddocr提供的训练接口对模型进行微调,以提升在该特定场景下的准确率。
  3. 备用方案:集成一个商业OCR API或打码平台作为备用,当ddddocr连续失败时启用。当然,这会增加成本和复杂度。

### 5.3 如何应对网站升级或增加新的验证机制?

这是自动化脚本的终极挑战。如果网站加入了滑块验证、点选验证等更复杂的交互式验证码,单纯的ddddocr+Selenium组合可能就不够了。

  • 滑块验证:可以尝试分析滑块缺口位置(通过图像比对算法),然后使用Selenium的ActionChains模拟拖动。但现代滑块验证往往有轨迹检测,需要生成符合人类加速度的拖动轨迹。
  • 点选验证:需要识别图中要求点击的目标(如“请点击图中的自行车”),这涉及到目标检测,可以使用YOLO等轻量级模型,但实现复杂度陡增。
  • 行为验证:如Google reCAPTCHA v3,它通过分析用户与网站的整个交互行为来评分。对抗这类验证非常困难,通常需要更底层的浏览器自动化工具(如puppeteer-extra-plugin-stealth)来深度隐藏自动化特征。

面对这些情况,一个务实的建议是:评估绕过成本。如果只是为了预约讲座,而网站升级导致自动化成本过高,或许回归半自动化(人工处理验证码,脚本处理其他步骤)或寻找其他合法途径(如关注是否有其他预约渠道)是更明智的选择。

### 5.4 关于效率与并发的思考

有同学可能会想,能否同时运行多个脚本实例,或者用多线程/多进程来提高抢票成功率?这是一个需要极度谨慎的领域。

  • 风险:从同一IP地址发起过高频、并发的请求,极易被服务器识别为恶意攻击,导致IP被封禁,甚至账号被锁定。
  • 建议:本项目的设计初衷是“辅助工具”,而非“攻击工具”。因此,我强烈建议单实例、低频率运行。它的价值在于解放你的双手和注意力,在预约开始时自动、准确地执行操作,其效率已经远超人工。试图通过技术手段进行不公平的资源争夺,违背了项目的初衷,也带来了不必要的风险。

最后,我想分享一点个人体会。开发这个脚本的过程,本身就是一个绝佳的实践项目。它串联起了网络爬虫、自动化测试、图像识别、系统集成等多个知识点。更重要的是,它让我深刻体会到,技术是一把双刃剑,其价值取决于使用者的意图。用技术去解决一个真实世界的小痛点,并在过程中不断学习、调试、优化,这种成就感远大于单纯“抢到一张票”。希望这个项目分享,能为你提供一些技术思路和启发,同时也提醒大家,在享受技术便利时,务必心怀善意,遵守规则。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询