Python+Selenium自动化抢课:绕过问卷星智能验证的实战指南
1. 环境准备与基础配置第一次用PythonSelenium抢课时我盯着屏幕等到凌晨两点结果手速还是慢了半拍。后来发现用自动化脚本能轻松搞定成功率直接提升到99%。先说说基础环境搭建这是整个项目的基石。Chrome浏览器是必备工具实测兼容性最好。安装时建议选择稳定版别用测试版给自己挖坑。Python环境推荐3.7版本太老的版本可能会遇到依赖问题。用以下命令检查版本python --versionSelenium库安装很简单pip install selenium最关键的ChromeDriver驱动文件必须与浏览器版本严格匹配。在Chrome地址栏输入chrome://version查看版本号然后到淘宝镜像站下载对应驱动。我遇到过驱动版本不匹配导致脚本报错的情况折腾了半天才发现问题所在。驱动文件解压后需要放在系统PATH路径比如Windows用户直接扔到Python安装目录Mac/Linux用户建议放/usr/local/bin2. 反检测技巧实战问卷星的智能验证机制越来越复杂去年还能简单绕过现在需要组合拳。通过Chrome DevTools Protocol(CDP)可以修改浏览器指纹这是目前最有效的方案。核心代码片段option webdriver.ChromeOptions() option.add_experimental_option(excludeSwitches, [enable-automation]) option.add_argument(--disable-blink-featuresAutomationControlled) browser webdriver.Chrome(optionsoption) browser.execute_cdp_cmd(Page.addScriptToEvaluateOnNewDocument, { source: Object.defineProperty(navigator, webdriver, {get: () undefined}) Object.defineProperty(navigator, plugins, {get: () [1,2,3]}) })实测有效的其他技巧随机化鼠标移动轨迹用ActionChains模拟人类操作添加随机延迟特别是在页面跳转时修改浏览器窗口尺寸window-size1366,768禁用GPU加速--disable-gpu减少特征值3. 定时抢课核心逻辑抢课最关键的是时间控制差0.1秒可能就满员了。Python的定时方案我测试过三种简单轮询适合新手while True: now time.strftime(%H:%M:%S) if now 08:00:00: # 开抢时间 start_script() break time.sleep(0.1)APScheduler推荐方案from apscheduler.schedulers.blocking import BlockingScheduler sched BlockingScheduler() sched.scheduled_job(date, run_date2024-03-15 08:00:00) def timed_job(): start_script() sched.start()系统级定时任务最稳定Windows用任务计划程序Mac/Linux用crontab我最终选择APScheduler系统定时双保险实测在校园网波动环境下也能准时触发。记得提前5分钟启动脚本处理可能的网络延迟。4. 表单自动化填写技巧不同类型的表单字段需要特殊处理这是最容易出错的环节。分享几个实用代码片段文本输入框# 姓名学号等基础字段 browser.find_element(By.ID, q1).send_keys(张三) browser.find_element(By.NAME, student_id).send_keys(20240001)单选按钮# 随机选择防止被检测 import random options browser.find_elements(By.CSS_SELECTOR, .radio-group input) options[random.randint(0, len(options)-1)].click()下拉菜单from selenium.webdriver.support.select import Select select Select(browser.find_element(By.ID, department)) select.select_by_visible_text(计算机学院)文件上传# 隐藏的input元素需要特殊处理 upload browser.find_element(By.XPATH, //input[typefile]) upload.send_keys(os.getcwd()/avatar.jpg)验证码处理简易版# 滑块验证码方案 try: slider browser.find_element(By.CLASS_NAME, nc_iconfont) ActionChains(browser).drag_and_drop_by_offset(slider, 300, 0).perform() except: pass5. 异常处理与日志记录脚本在凌晨运行时崩溃是最糟心的完善的错误处理能省去很多麻烦。这是我的日志方案import logging from selenium.common.exceptions import NoSuchElementException logging.basicConfig( filenameauto_register.log, levellogging.INFO, format%(asctime)s - %(levelname)s - %(message)s ) try: # 主要业务逻辑 submit_form() except NoSuchElementException as e: logging.error(f元素未找到: {str(e)}) browser.save_screenshot(error.png) except Exception as e: logging.critical(f未知错误: {str(e)}, exc_infoTrue) finally: browser.quit()推荐监控的关键点页面加载超时设置page_load_timeout30元素查找失败增加重试机制表单提交状态检查返回结果网络波动自动重连6. 高级优化技巧当基础功能跑通后这些优化能让你的脚本脱颖而出多窗口并行from threading import Thread def worker(url): driver webdriver.Chrome(optionsoptions) driver.get(url) # 填写逻辑... threads [] for i in range(3): # 同时开3个窗口 t Thread(targetworker, args(url,)) threads.append(t) t.start()代理IP轮换PROXY 12.34.56.78:8080 options.add_argument(f--proxy-server{PROXY})无头模式部署options.add_argument(--headless) options.add_argument(--disable-gpu) options.add_argument(--no-sandbox)自动化测试套件import unittest class TestRegistration(unittest.TestCase): def test_form_submit(self): # 测试用例 self.assertTrue(submit_success)7. 实际案例剖析去年帮学校社团抢讲座场地时遇到个棘手问题提交前突然弹出新验证选择所有包含公交车的图片。通过分析网络请求发现可以直接跳过这个环节# 拦截验证请求 browser.execute_cdp_cmd(Network.setRequestInterception, { patterns: [{ urlPattern: *captcha*, interceptionStage: HeadersReceived }] }) # 修改响应 browser.execute_cdp_cmd(Network.continueInterceptedRequest, { interceptionId: interception_id, rawResponse: bHTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n })这个方案虽然有效但需要定期维护。更稳妥的做法是准备两套方案主方案快速提交绕过验证备用方案遇到新验证时自动发送邮件通知最后分享个真实数据用优化后的脚本在300人竞争中抢到前5个席位平均耗时1.7秒比手动操作快8-10倍。关键是要模拟人类操作节奏太快反而容易被封。