发布时间:2026/9/2 1:58:48
Python抢号脚本核心原理:Session、定时调度与重试机制全解析 简介这份资源是一套基于Python的医院挂号自动抢号脚本代码包面向想要学习浏览器自动化与验证码识别的Python开发者也适合有实际挂号需求的人参考。脚本以华西医院网页为例使用Selenium模拟浏览器打开登录页自动发送并处理手机验证码完成登录后设置倒计时在指定时间准时进入医生主页随后选择电子健康卡并借助ddddocr识别图形验证码自动填入最后通过循环检测确认按钮完成预约。资源共6个文件压缩包仅8KB包括py主程序、config.ini配置、requirements.txt依赖清单、demo.html示例页面、inscode配置文件和md/txt说明文档结构简洁便于快速阅读。代码提供了完整思路和关键片段涵盖元素定位、显式等待、验证码识别、异常重试等自动化难点同时针对页面加载延迟和按钮未出现等情况加入了轮询与重试机制帮助提升挂号成功率。目前已有343人学习下载读者可根据自身需求修改参数或将该思路迁移到其他定时预约、抢购等场景。 很多朋友私信我上来就是一句能不能给我写一个Python医院抢号脚本带代码的那种。搜一下“Python医院抢号脚本[代码]”这个标题各种文章、帖子确实不少但真正把原理讲清楚、能让人举一反三的几乎没有。这篇文章我打算换个思路不直接给你一份“复制就能用”的抢号代码那种代码要么几天就失效要么本身有合规风险而是把这类型脚本背后的核心模块、关键技术点、工程化设计拆开来讲最后给出一套不依赖任何真实医院接口、可本地跑通的调度框架Demo。适合对Python网络请求、自动化调度有一定基础想理解这类工具本质的开发者。1. 先说清楚这类脚本到底在忙什么1.1 核心模块拆解从身份凭证到预约提交的完整链路一段看似不起眼的“抢号脚本”落到工程层面其实是四个独立模块的协作产物。第一个是身份模块。医院预约系统几乎都是登录后操作脚本必须持有你的登录凭证。常见做法是用requests.Session()维持Cookie或者在登录后保存Token后续每个请求都带上。别小看这一步很多人脚本跑不通不是请求逻辑写错了而是Session没有正确保持服务端根本不认这个“人”。第二个是查询模块。脚本要反复访问号源查询接口拿到某个科室、某个医生的剩余号量。这里涉及接口地址、请求参数日期、科室ID、医生ID、响应解析。医院系统的前端页面每一次改版接口返回的JSON结构都可能变所以这个模块是维护成本最高的地方。第三个是动作模块。查到位之后真正提交预约的动作通常是一个POST请求参数里包含号源ID、就诊人ID、时间段等。动作模块要处理的是一致性问题你查到的号源可能在提交前的一瞬间被别人抢走了这时服务端会返回“号源已满”或“冲突”脚本需要捕获并处理这种竞态。第四个是通知模块。抢到没抢到得让用户知道。简单的是写日志、发邮件常见的是接入企业微信机器人、钉钉机器人或Server酱把结果推到手机上。把这四个模块串起来才是一个完整的“抢号脚本”该有的骨架。很多人上网求代码拿到的往往只有查询和提交两段身份和通知模块都是残缺的自然跑不起来。1.2 为什么它不是“写个循环”那么简单有一种常见的误解抢号不就是while True: requests.get(查号接口)查到就提交嘛。真这么简单就不需要专门写工程脚本了。真实场景里至少有三个问题。第一查询频率不能无限高。你每秒钟打一次接口服务器会压力很大风控系统也会盯上你轻则当前IP被限流重则账号被标记。第二不是查到了就一定能提交成功。从查询到提交是一个“检查再更新”的竞态窗口别人可能正好在你查询之后、提交之前抢走了号源。这也是为什么很多脚本设计成查询到号源后立刻用同一个请求上下文去提交而不是等用户确认。第三参数是动态的。你以为接口地址不变就万事大吉实际上一段时间后服务端可能给请求参数加了签名、时间戳、加密字段原有脚本全部失效。所以“抢号脚本”本质上是一个带状态、带频率控制、带容错重试的Web自动化程序。理解到这一层你才能看懂后面所有的技术选型。以下所有内容都默认你已经理解了这一层我直接进入关键技术点。2. 关键技术点逐个拆身份保持、任务调度与请求容错2.1 Session与Cookie怎么让服务器认出“你是你”HTTP协议本身是无状态的服务器不记得你上一个请求干了什么。Session机制的出现就是为了解决这个问题你登录成功后服务器返回一个Cookie后续请求只要带上这个Cookie服务器就知道“你是同一个已登录用户”。在Python里requests.Session()是处理这件事最顺手的工具。它做了两件好事自动保存和附带Cookie以及复用底层TCP连接减少握手开销。很多新手栽的坑是每次请求都用requests.get()裸调登录接口返回的Cookie没有保存下一次请求服务端直接返回401或登录页。一个稳妥的做法是import requests session requests.Session() login_url https://your-api.example.com/api/login login_payload {account: your_account, password: your_password} resp session.post(login_url, jsonlogin_payload, timeout10) # 登录成功后session里自动存了Cookie和必要的身份信息 # 后续所有请求都用这个session对象如果服务端返回的是Token而不是Cookie那就在每次请求头里带上Authorization: Bearer token。这种设计在移动端App接口里更常见本质上一样你只需要维护一个全局的请求头工厂就行。有人会问JWT Token不是无状态的吗还需要Session吗在实际工程里医院系统往往是“Token 服务端会话”混合使用你没必要纠结理论模型实践原则只有一个把身份信息和请求上下文封装成一个可复用的对象别在每个函数里重复登录。2.2 时间基准与定时调度抢的其实是“时间窗口”这类脚本的核心竞争点就是时间窗口。医院放号时间往往是固定时间点脚本需要在放号瞬间发出请求。那你首先得保证脚本所在机器的时钟和服务端时钟一致。本地电脑时间慢了两秒放号瞬间你还在等本地时钟走到点实际上服务端已经放号两秒了热门号源早就没了。解决思路很简单在放号前做一次时间同步。可以用requests去请求一个标准时间接口解析返回的时间戳来校正本地偏移量调度器按校正后的时间触发任务。在代码层面写一个轻量的时间校正函数import time import requests def get_server_offset(server_time_url: str) - float: 返回服务端时间与本地时间的差值秒本地慢则为正 resp requests.get(server_time_url, timeout5) server_ts resp.json()[timestamp] # 假设接口返回标准时间戳 return server_ts - time.time()这个offset可以在放号前几秒获取一次然后在调度等待逻辑里用上。注意别频繁请求时间接口那会给自己带来不必要的限流风险。定时调度方面简单场景用time.sleep()就够了但如果你有多个监控任务、需要按cron表达式跑还是老老实实用APScheduler。它支持interval和cron两种触发方式配合BlockingScheduler或BackgroundScheduler可以灵活嵌入不同项目。后面第3章我会给一个可跑的调度框架。2.3 并发与重试快不一定赢稳才不封很多初学者拿到需求后的第一反应是开多线程50个线程同时查接口似乎“抢”到的概率更高。实际效果往往相反所有线程都卡在等待响应上服务器一看同一个IP瞬间涌进来几十个请求直接触发限流连正常请求都被拒掉。正确的做法是用有限并发 超时控制 指数退避重试把请求频率控制在安全线以内。这里我给一个很实用的Session封装使用urllib3的Retry机制对超时和5xx错误做自动重试import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry def build_session_with_retry(retries: int 3, backoff_factor: float 1.0): session requests.Session() retry Retry( totalretries, connectretries, readretries, backoff_factorbackoff_factor, # 每次重试等待backoff_factor * (2 ** retry_count) status_forcelist[429, 500, 502, 503, 504], allowed_methods[GET, POST], ) adapter HTTPAdapter(max_retriesretry) session.mount(http://, adapter) session.mount(https://, adapter) return session注意backoff_factor的语义假设重试等待时间为backoff_factor * (2 ** 当前重试次数)所以设成1.0第一次重试等2秒第二次4秒第三次8秒。指数退避的核心思想是一旦服务端不稳定立刻把请求频率降下来让服务端喘口气而不是疯狂重试加剧问题。如果你是做查询监控用单线程或双线程就够了重点在“稳定地间歇请求”而不是“瞬时高并发”。2.4 验证码这道坎自动化与公平的边界所有抢号类脚本最绕不开的就是验证码。滑块验证码、点选验证码、短信验证码层层加码之后纯HTTP请求已经很难独立完成全流程。这里我说句透底的话任何针对真实业务系统的验证码自动识别方案我都不建议写也不建议用。验证码存在的意义就是区分人和自动化工具。你写代码绕过验证码本质上就是在和服务端的安全策略对抗。工程上碰到验证码正确的处理姿势是代码里识别到“需要验证”的响应特征后立即停止后续自动操作通过通知模块把“需要人工过验证码”这个信号推给用户。比如if captcha in resp.text or resp.status_code 460: # 示例状态码 notify(检测到验证码需要人工介入) return这套逻辑放在正规自动化测试里也成立测试环境一般通过白名单、测试后门或人工介入来处理验证码不会在线上环境硬破解。理解了这条边界你在设计调度框架时就不会把“打码平台”这类灰色方案当核心模块来耦合。3. 一套可复现的调度框架示例号源余量监控提醒器3.1 框架定位只监控、不抢先跑通调度逻辑为了让你能安全地跑通整套思路我设计了一个“号源余量监控提醒器”。它不绑定任何真实医院系统只演示三件事定时轮询一个接口、解析返回状态、状态变化时触发通知。这套逻辑就是所有抢号脚本最核心的骨架你完全可以改成查余票、查库存、查设备状态。演示环境用的是https://httpbin.org/delay/1它会延迟1秒返回JSON用来模拟一个真实的慢接口。先装依赖pip install requests apscheduler3.2 请求执行器Session、超时与重试的封装请求执行器是整个框架的底座负责所有HTTP请求的发送、超时控制和重试。直接上一段完整代码import logging import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry logging.basicConfig(levellogging.INFO, format%(asctime)s %(levelname)s %(message)s) def build_session_with_retry(retries: int 3, backoff_factor: float 1.0) - requests.Session: session requests.Session() retry Retry( totalretries, connectretries, readretries, backoff_factorbackoff_factor, status_forcelist[429, 500, 502, 503, 504], allowed_methods[GET, POST], ) adapter HTTPAdapter(max_retriesretry) session.mount(https://, adapter) session.mount(http://, adapter) return session def fetch_data(session: requests.Session, url: str) - dict: resp session.get(url, timeout5) resp.raise_for_status() # 4xx/5xx会抛出异常由重试机制接手 return resp.json()这里有一个容易忽略的点raise_for_status()会主动抛出HTTP错误配合Retry才能触发重试。如果你自己写了try/except把异常吞掉重试机制就不会生效。3.3 轮询任务与通知钩子接下来是核心的检查逻辑和通知逻辑。我用一个假设的接口响应结构来演示实际使用时把CHECK_URL换成你自己合法有权访问的接口即可CHECK_URL https://httpbin.org/delay/1 def check_and_notify(): session build_session_with_retry() try: data fetch_data(session, CHECK_URL) # 假设接口返回里有个字段标识“当前可预约数量” available_count data.get(available, 0) if available_count 0: notify(f检测到可预约号源剩余 {available_count} 个) else: logging.info(当前无余量继续监控) except requests.RequestException as e: logging.warning(f请求失败{e}) def notify(message: str): # 这里先打日志实际项目可以替换成企业微信机器人、邮件或短信 logging.info(f[NOTIFY] {message})主调度用APScheduler实现每30秒检查一次from apscheduler.schedulers.blocking import BlockingScheduler def main(): scheduler BlockingScheduler(timezoneAsia/Shanghai) scheduler.add_job(check_and_notify, interval, seconds30) scheduler.start() if __name__ __main__: main()BlockingScheduler会阻塞主线程适合独立脚本。如果你想把监控任务嵌进已有的Web服务改用BackgroundScheduler即可。3.4 本地跑通的验证方式直接运行上面这段代码你会看到日志里每30秒输出一次“当前无余量”这是因为httpbin.org的响应里根本没有available字段data.get(available, 0)取到的默认值是0。这正说明了一个重要机制框架是通的只是你的“业务字段解析”和真实接口不匹配。想真正验证通知逻辑可以换一个返回自定义JSON的本地Mock服务。用Flask起一个几行的接口from flask import Flask, jsonify import random app Flask(__name__) app.route(/api/quota) def quota(): return jsonify({available: random.randint(0, 3)}) app.run(port5000)然后把CHECK_URL改成http://127.0.0.1:5000/api/quota再把轮询间隔改成10秒。这样你能很快观察到[NOTIFY]日志出现完整走通“轮询—解析—通知”的链路。先跑通这套后面的问题排查才有基础。4. 实测中容易翻车的细节与应对思路4.1 接口返回结构变化解析层必须做容错做这类脚本最崩溃的事不是请求失败而是请求突然“成功”了但解析不到你要的数据。医院系统或者任何业务系统前端一改版接口返回的字段名就可能从number变成remain_count旧脚本直接KeyError或者解析出None。我的习惯是解析层全部用get()加默认值不加裸下标访问并且对关键字段缺失记WARN日志。上面的示例里data.get(available, 0)就是这么做的。你会发现这样写出来的脚本在字段变化时不会崩溃只是拿不到值日志会提示你“字段可能变了”方便你更新解析逻辑。4.2 限流与封禁不是请求越多越好请求频率控制是另一道生死线。服务端常见的限流表现是某个IP在短时间内请求次数超过阈值后续请求直接返回429 Too Many Requests或者干脆返回空数据。这属于服务端的自我保护脚本如果不认识这个信号会一直重试最后被临时封禁IP。下表是我在实际项目中总结的常见表现和应对思路现象可能原因应对思路返回429请求频率过高降低轮询间隔加指数退避重试偶尔超时接口性能波动增加超时时间重试放宽返回数据为空参数错误或接口升级重新核对请求参数和接口文档需要验证码触发风控停止自动操作转人工处理也就是说脚本设计阶段就应该假设请求大概率失败而不是假设每次都能成功。我见过的很多翻车事故本质都是把“监控”做成了“攻击”频率一高账号和IP一起凉。4.3 验证码与风控升级自动化遇到“人工校验”在真实系统里验证码不是静态的它会升级。之前可能只是图形验证码后来变成滑块再后来变成需要手机短信二次确认。这种升级在响应里的表现通常是接口返回一个特殊状态码或者响应体里出现captcha、verify等关键字。我在框架里专门预留了“检测到验证码就停止并通知”的钩子就是因为它太容易翻车了。很多脚本不是死在请求上而是死在验证码出现后仍然无脑重试最后被系统判定为恶意请求。记住一旦检测到验证码立刻降级为人工处理这是最稳妥的兜底策略。4.4 环境与依赖问题命令找不到、依赖装不上最后说一个特别新手向但出现率极高的问题。很多人在Windows上下载了Python、写好了脚本一运行却报“无法将‘python’项识别为 cmdlet、函数、脚本文件或可运行程序的名称”或者运行claude、pip之类的命令时提示找不到。这几乎都是环境变量没配对系统找不到Python的可执行文件路径。解决办法不复杂安装Python时勾选“Add Python to PATH”装完后重开终端如果之前没勾选去“系统属性—环境变量—Path”里手动把Python安装目录和Python安装目录\Scripts加进去。依赖装不上的时候优先检查是不是pip源网络问题可以用国内镜像源装pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple。这类问题属于基础设施问题配置好了能省掉后面一大半的折腾。5. 合规边界与技术用途延伸5.1 为什么不直接贴一份“能用的抢号代码”到这一步你大概能理解我为什么坚持不给一份“复制就能用”的真实抢号代码了。这类代码有三个绕不开的硬伤。第一有效期极短。业务系统接口一改脚本立刻报废这份代码对你没有任何长期价值。第二维护成本高。你要持续跟进接口变化、风控升级等于每天都在和平台安全策略赛跑。第三公平性问题。预约号源是稀缺资源自动化脚本本质上是在挤占其他普通用户的候诊机会。技术可以用来提升效率但用在零和博弈的场景里副作用会被放大。所以我前面所有内容都在讲原理、讲工程框架而不是给一套针对某个真实系统的“抢”代码。你真正该带走的是监控轮询、容错重试、身份保持这些通用能力这些能力在任何一个合法场景都能复用。5.2 同一套技术栈的正确打开方式把上面这套调度框架改一改就能落到很多合规场景里。举三个我自己做过的方向第一个是号源余量提醒。只查询、不提交发现有余量就第一时间推送通知由用户自己打开App或小程序完成预约。这个方案完全站在辅助用户的一侧不破坏公平性而且技术难度低很多。第二个是接口健康巡检。定时探测公司内部服务的健康检查接口响应变慢或返回错误时自动告警这就是一个非常标准的可观测性小工具。第三个是自动化冒烟测试。把核心业务链路用脚本串起来定时跑一遍失败就发通知这也是自动化测试落地的最低成本形态。我自己做自动化多年最大的体会是自动化是用来解决重复劳动的不是用来和规则对抗的。把请求调度、容错重试、状态机设计这些基本功练好你会发现需要写脚本的场景永远不缺。那些靠绕过风控、抢占资源做的事既走不远也带不来真正的技术积累。本文还有配套的精品资源点击获取

相关新闻

2026/9/2 1:58:48

SQLite可靠性设计:从日志机制到应用层防御实践

1. 为什么 SQLite 的可靠性经验值得单独拿出来讲 数据库可靠性不是一个抽象口号,而是由文件格式、事务日志、锁策略、损坏检测、备份恢复、测试手段等一系列工程决策共同支撑起来的结果。SQLite 作为全球部署量最大的嵌入式数据库,几乎运行在每一台智能手…

2026/9/2 1:58:48

Applebot爬虫如何意外成为安全LLM的模糊测试场?

1. 先搞清楚这个标题到底在说什么看到“Did Apple Search engine bot enter the security LLM fuzzing gauntlet”这个标题,第一反应可能是“苹果的搜索引擎爬虫和安全大语言模型模糊测试有什么关系?”。这很正常,因为标题本身像是一个技术圈…

2026/9/2 1:53:48

Python+ESP32温湿度监测实战:从AHT20采集到SQLite存储

简介:该压缩包是一套Python温湿度数据测量、处理与数据库存储的实战资源,适合学习物联网数据链路的开发者。项目覆盖硬件通信、数据解析、清洗校验到数据库写入的流程,主控、库连接、CRC校验、数据上报等模块齐全。压缩包共十四个文件&#x…

2026/9/2 2:08:48

英伟达机器人生态解析:CUDA打法与人形机器人开发环境搭建指南

大家好,我是你们的老朋友。最近科技圈有一条消息引发了不少讨论:中国人形机器人企业占全球相关企业总数的 86% 左右,在产业链成熟度、融资规模和应用场景落地速度上都跑在了前面。与此同时,英伟达在布局机器人领域时,被…

2026/9/2 2:08:48

京东前端面试全流程复盘:JavaScript、Vue与性能优化核心考点

1. 从投简历到Offer:京东前端面试全流程复盘先说结论:京东2024前端面试整体给我的感觉是——基础考察非常扎实,项目追问极其细致,手写代码是硬门槛,算法题难度属于中等偏上但不会故意刁难人。如果你正在准备大厂前端岗…

2026/9/2 2:08:48

XYHCMS v3.5 build0518 实测:部署、模板与升级避坑指南

简介:XYHCMS v3.5 build0518 是一款基于 PHP 与 MySQL 的开源网站管理系统源码包,主要面向个人博客、企业建站及个性化站点开发者,也适合希望快速掌握 CMS 安装与后台管理的非技术用户。系统采用分层架构与 MVC 设计,将数据处理、…

2026/9/2 2:08:48

ECShop码支付插件部署实战:从签名机制到异步回调的支付接入指南

简介:一份面向ECShop商城开发者的码支付集成插件,帮助B2C站点在不与支付宝、微信、财付通逐一签约的前提下,快速接入三种主流电子支付方式。插件整合了码支付的二维码交易链路,用户扫码即可完成付款,适合追求低成本上线…

2026/9/2 2:08:48

分区助手绿色版:无损扩容C盘与系统迁移实战

简介:这是一款面向个人用户与系统维护人员的磁盘分区管理工具绿色版,无需安装即可直接运行,重点解决C盘空间不足、分区容量失衡及磁盘重新规划等常见问题。资源包共55个文件,大小仅7.82MB,其中主要包含PartAssist主程序…

2026/9/2 2:03:48

OpenGL入门必看:Glad加载器与GLFW上下文配置详解

简介:GLAD 5.8(64位)激光与物理光学设计软件的演示版资源包,专为激光器建模、光束传播与光学系统仿真而开发,适合从事激光器研发、光学元件设计及物理光学教学的高校师生和工程师学习使用。压缩包内共1059个文件、大小…

2026/9/1 16:02:17

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/1 8:27:47

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/1 7:04:43

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/2 0:03:41

单片机毕业设计-基于单片机与蓝牙通讯的输液状态监测终端设计与开发 基于 STM32 或 51 单片机的液位‑滴速‑温度多参数输液监护装置设计(024005)

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于嵌入式单片机,Java、小程序技术领域和毕业项目实战 ✌️…

2026/9/2 0:03:41

DeepSeek字幕翻译实战:从API调用到批量SRT转中文的完整方案

这次我们来看一个很实用的 DeepSeek 落地场景:用 DeepSeek 把英文视频字幕自动翻译成中文。具体案例是《恶魔君》1989 年第 28 集的英转中字幕任务,标题写得很直白,但背后其实是一整套可以复用的技术流程:字幕解析、模型调用、批量…

2026/9/2 0:03:41

用Python搭建搞笑语音助手:从语音识别到语音合成全教程

当你家里摆着一台天猫精灵,却总希望语音助手偶尔“不正经”一点,不用官方腔回答问题,而是张口就接几句搞笑段子,会是什么体验?我最近动手验证了一下这个想法——没有去改装任何市面上现有的智能音箱,而是直…

2026/9/2 1:15:22

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/2 1:15:22

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/2 1:15:20

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…