Python自动实时查询预约网站的剩余名额并在有余额时发邮件提示
本文介绍基于Python语言,自动、定时监测某体检预约网站中指定日期的体检余额,并在有体检余额时自动给自己发送邮件提醒的方法。
来到春招末期,很多单位进入了体检流程。其中,银行(尤其是四大行)喜欢“海检”,即差额体检——收到体检不代表录取的那种;而正巧我春招主要报名的就是银行、国企等,所以单是这周就有4
家单位发了体检通知。
其中,有的单位需要自费体检。在这周4
家单位中,交通银行就需自费(我报的还是总行呢)——关于银行的体检,大家可以参考文章建信金融科技软开工程师24届Offer面经(https://blog.csdn.net/zhebushibiaoshifu/article/details/135352867)。贫穷的我自然想到了直接用我们研究所发的免费体检来充当单位体检了——所里每年上半年会提供1
次免费体检的机会,往年我都是第一时间就去体检;但今年就是想着可以将其充当入职体检,所以迟迟没有去。因此,这次看到交行的自费体检,就想着预约所里给的这个免费体检——等的就是这一天,能省则省。但是,当我打开所里体检的预约网页后,发现我1
个堂堂男学生,竟然最近几天已经没有体检名额了,如下图所示。
但是,交行给出的体检报告提交截止时间也比较近,所以必须要预约到上图中最近几天的体检;因此,选择用Python监控这几天的体检名额,且若发现最近几天有名额,就给我自己发邮件。当然,更好、更完整的操作是,只要发现最近几天有名额,就直接由程序自动实现预约——但一方面,这个需求若想实现,还得进一步研究后续提交预约时的HTTP请求信息,我太菜了,这个对我而言可能比较麻烦;另一方面,在准备开始写脚本时正好收到了中国星网的体检,他们是无需自费且提供体检报告的那种体检,所以可以直接把星网的体检报告发给交行,相当于暂时又用不到所里的体检了。所以我后来也就没再继续探究上述这个更进一步的需求的实现方法——当然,后面如果有机会,可以再进一步研究一下。
知道了需求,即可开始尝试实现。首先,虽然所里体检的预约流程主要是在手机上进行的,但它也还是一个普通的网页,而非小程序;较之小程序,网页实现起来或许会更容易一些——当然,我也没做过小程序的爬虫,也并不知道小程序的话到底是会更复杂还是更容易;但网页的话,至少流程、思路方面还是比较清晰的。
我们先查看上图中所示网页的HTML,也就是能显示哪一天是否可预约体检的那个网页的HTML,如下图所示。可以看到,这个网页的HTML(下图)并不含有每一天的预约余额信息(上图),也就是说这些预约余额信息应该是JavaScript动态加载的。
接下来,我们按下F12
键进入浏览器的开发者工具,并选择“Network”;随后,重新刷新当前网页,并观察出现的每一个元素;如下图所示。
通过观察,找到了具有每天体检余额信息的那1
个元素,如下图所示。
随后,查看这个元素的信息,如下图所示。可以看到,这是1
个POST请求,具体的请求Headers也是比较常规的。
这里提一句,我一开始看到这个POST请求的Headers具有伪头部(也就是上图中右下角紫色框内,排在前4
个的、Key前带有冒号:
的头部),说明其是HTTP/2的请求;所以当时还以为不能用Python的requests
库了,然后hyper
库又不维护了,所以已经准备用HTTPX
库来实现需求了。但是后来发现,requests
库还是可以正常发送请求并获取回复,所以最后还是选择用更为方便的requests
库了。这里我也不太清楚requests
库不支持HTTP/2这句话是如何界定的。
接下来,我们首先撰写Python访问网页并获取体检名额余额的代码;这一部分代码具体如下。
# -*- coding: utf-8 -*-
"""
Created on Thu May 31 22:08:26 2024@author: fkxxgis
"""import smtplib
import requests
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipartdef send_email(subject, body, email_to):smtp_server = "smtp.qq.com"smtp_port = 465email_from = "你的发件邮箱"password = "你的邮箱的授权码(不是邮箱密码)"msg = MIMEMultipart()msg["From"] = email_frommsg["To"] = email_tomsg["Subject"] = subjectmsg.attach(MIMEText(body, "plain"))try:server = smtplib.SMTP_SSL(smtp_server, smtp_port)server.login(email_from, password)server.sendmail(email_from, email_to, msg.as_string())server.quit()print("Email sent successfully!")except Exception as e:print("Email sent failed!")url = "POST请求的链接"
url_in = "直达预约界面的链接,设置这个是为了方便从邮件中直达预约网页"
date_need = ["2024-06-03", "2024-06-04", "2024-06-05"]headers = {"accept": "application/json, text/plain, */*","accept-language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7","content-type": "application/json;charset=UTF-8","cookie": "这里cookie太长了,我就删除了,大家理解即可","origin": "https://hosp.etong-online.com","priority": "u=1, i","referer": "https://hosp.etong-online.com/","sec-ch-ua": "\"Google Chrome\";v=\"125\", \"Chromium\";v=\"125\", \"Not.A/Brand\";v=\"24\"","sec-ch-ua-mobile": "?0","sec-ch-ua-platform": "\"Windows\"","sec-fetch-dest": "empty","sec-fetch-mode": "cors","sec-fetch-site": "same-origin","user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36"
}data = {"batchCode": "3797","unitCode": "0521","institutionCode": "04010802","token": "xDMxsuTNeHhY8MbYqKEa9A=="
}response = requests.post(url, headers = headers, json = data)if response.status_code != 200:print ("Access error!")
else:response_json = response.json()for date in date_need:for item in response_json['data']:if item['scheduleDate'] == date:if item['stockQuantity'] != 0:print(f"Date {date} has stock quantity: {item['stockQuantity']}")subject = f"在{date}这天体检有名额了!"body = f"目前{date}的体检有{item['stockQuantity']}个名额,可以看看要不要预约;若需预约请点击{url_in} 。"email_to = "你的收件邮箱"send_email(subject, body, email_to)else:print(f"Date {date} has no stock quantity.")break
其中,代码的大致流程也比较清晰。首先定义send_email()
函数,用于给自己发送电子邮件;该函数需要提供邮件主题、正文和收件人邮箱地址。随后的部分,就是发送那个可以返回体检名额余额的POST请求,其中的headers
部分大家就复制前述浏览器开发者工具中,这个请求的Request Headers就好,data
部分则复制Request Payload就好。
随后,遍历指定日期,检查每个日期是否有剩余预约名额;如果某日期有剩余的预约名额,则打印1
条消息并通过电子邮件发送通知——邮件中包括具有体检余额的日期、名额数量与预约链接等。这里需要注意,如果这个提醒邮件是发给我们个人,就需要自己有2
个邮箱(QQ邮箱1
个人可以注册多个域名,不同域名的邮箱之间就可以互发邮件)——其中一个作为发件地址,另一个作为收件地址。
我们如果此时执行上述代码,即可看到指定日期内体检名额的剩余情况。其中,如下图所示,某次执行后,发现06
月03
日这一天有体检的名额了(原本写代码时06
月03
日还是没有名额的,这说明有1
位同学预约了这一天但是现在取消了)。
那么,邮箱中就会收到如下图所示的提醒邮件。如果大家开启了类似微信的邮件实时提醒,或手机端邮箱APP的应用消息通知,那么相当于就是实时接收体检余额的提醒了。
为了方便,我们也将体检预约的网页链接放在了邮件中,如下图所示;点击后即可进入预约。
进入预约网页内,发现果然06
月03
日这一天,当前是可以预约的。如果有需要的话,此时就可以手动预约了。
当然,上述我们是单次执行程序。如果希望可以在后台定时对体检余额加以检测(例如我想每隔30
分钟就自动查询1
次),则可以通过如下代码来实现。
# -*- coding: utf-8 -*-
"""
Created on Sat Jun 1 16:04:04 2024@author: fkxxgis
"""import time
import datetime
import schedule
import subprocesscount_num = 0def run_script():global count_numcount_num += 1current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")print(f"At {current_time}, the script has been run {count_num} time(s).")result = subprocess.run(["python", "check.py"], capture_output = True, text = True)print(result.stdout)if result.stderr:print(result.stderr)schedule.every(30).minutes.do(run_script)
run_script()while True:schedule.run_pending()time.sleep(1)
上述代码通过schedule
库,使得我们可以每30
分钟运行1
次run_script()
函数,而这个函数就是用来执行本文前述的那一段监测余量、发送邮件的代码——也就是上述代码中的check.py
文件;这里因为我将2
个Python代码文件放在同一路径下了,所以就用了相对路径。
随后,通过手动调用1
次run_script()
函数,使得程序开始时先执行1
次查询,然后再每隔30
分钟查询1
次。代码最后,进入1
个无限循环,并在循环中调用schedule.run_pending()
函数,确保按预定计划运行run_script()
函数;同时,在每1
次循环中,脚本会休眠1
秒钟,避免占用太多CPU资源。
完成上述代码后,执行这一文件,即可看到已经按照要求,每隔30
分钟查询1
次体检余量了。
如果查询过程中,发现指定日期出现了体检名额,那么和本文前述内容一样,程序会自动给我们发邮件,提醒我们可以预约了。这里大家可以结合自己的使用场景与个人需求,修改每次查询的间隔时间;但是建议不要间隔的时间太短,否则可能会被网站的服务器屏蔽。
当然,还是那句话,本文这里的代码只能自动监控余量并加以邮件提醒,而没有实现发现余量后自动预约。如果大家感兴趣,可以进一步实现自动预约的需求。
至此,大功告成。
欢迎关注:疯狂学习GIS
相关文章:

Python自动实时查询预约网站的剩余名额并在有余额时发邮件提示
本文介绍基于Python语言,自动、定时监测某体检预约网站中指定日期的体检余额,并在有体检余额时自动给自己发送邮件提醒的方法。 来到春招末期,很多单位进入了体检流程。其中,银行(尤其是四大行)喜欢“海检”…...

Flutter 验证码输入框
前言: 验证码输入框很常见:处理不好 bug也会比较多 想实现方法很多,这里列举一种完美方式,完美兼容 软键盘粘贴方式 效果如下: 之前使用 uniapp 的方式实现过一次 两种方式(原理相同)࿱…...
如何从0到设计一个CRM系统
什么是CRM 设计开始之前,先来了解一下什么是CRM。CRM(Customer Relationship Management)是指通过建立和维护与客户的良好关系,达到满足客户需求、提高客户满意度、增加业务收入的一种管理方法和策略。CRM涉及到跟踪和管理客户的所…...

Numba 的 CUDA 示例 (2/4):穿针引线
本教程为 Numba CUDA 示例 第 2 部分。 按照本系列从头开始使用 Python 学习 CUDA 编程 介绍 在本系列的第一部分中,我们讨论了如何使用 GPU 运行高度并行算法。高度并行任务是指任务完全相互独立的任务,例如对两个数组求和或应用任何元素函数。 在本教…...
项目的各个阶段如何编写标准的Git commit消息
标准提交消息格式 一个标准的提交消息应包括三部分:标题(summary)、正文(description)和脚注(footer)。 1. 标题(Summary) 简洁明了,不超过50个字符。使用…...

Python课设-学生信息管理系统
一、效果展示图 二、前端代码 1、HTML代码 <1>index.html <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">…...

openssl 常用命令demo
RSA Private Key的结构(ASN.1) RSAPrivateKey :: SEQUENCE { version Version, modulus INTEGER, -- n publicExponent INTEGER, -- e privateExponent INTEGER, -- d prime1 INTEGER, -- …...

【Linux】Linux基本指令2
目录 1.man指令(重要): 2.echo指令 3.cp指令(重要): 4.mv指令 5.cat指令/echo指令重定向 6.more指令 7.less指令(重要) 8.head指令 9.tail指令 我们接着上一篇:h…...

springboot+vue+mybatis博物馆售票系统+PPT+论文+讲解+售后
如今社会上各行各业,都喜欢用自己行业的专属软件工作,互联网发展到这个时候,人们已经发现离不开了互联网。新技术的产生,往往能解决一些老技术的弊端问题。因为传统博物馆售票系统信息管理难度大,容错率低,…...

java—MyBatis框架
简介 什么是 MyBatis? MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&…...

如何使用Spring Cache优化后端接口?
Spring Cache是Spring框架提供的一种缓存抽象,它可以很方便地集成到应用程序中,用于提高接口的性能和响应速度。使用Spring Cache可以避免重复执行耗时的方法,并且还可以提供一个统一的缓存管理机制,简化缓存的配置和管理。 本文将详细介绍如何使用Spring Cache来优化接口,…...

大话C语言:第21篇 数组
1 数组概述 数组是若干个相同类型的变量在内存中有序存储的集合。 数组是 C 语言中的一种数据结构,用于存储一组具有相同数据类型的数据。 数组在内存中会开辟一块连续的空间 数组中的每个元素可以通过一个索引(下标)来访问,索…...

transfomer中attention为什么要除以根号d_k
简介 得到矩阵 Q, K, V之后就可以计算出 Self-Attention 的输出了,计算的公式如下: A t t e n t i o n ( Q , K , V ) S o f t m a x ( Q K T d k ) V Attention(Q,K,V)Softmax(\frac{QK^T}{\sqrt{d_k}})V Attention(Q,K,V)Softmax(dk QKT)V 好处 除以维…...

iperf3带宽压测工具使用
iperf3带宽压测工具使用 安装下载地址:[下载入口](https://iperf.fr/iperf-download.php)测试结果:时长测试(压测使用):并行测试反向测试UDP 带宽测试 iPerf3 是用于主动测试 IP 网络上最大可用带宽的工具 安装 下载地址&#x…...

[数据集][目标检测]焊接处缺陷检测数据集VOC+YOLO格式3400张8类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):3400 标注数量(xml文件个数):3400 标注数量(txt文件个数):3400 标注…...
2024华为OD机试真题-剩余银饰的重量-C++(C卷D卷)
题目描述 有 N 块二手市场收集的银饰,每块银饰的重量都是正整数,收集到的银饰会被熔化用于打造新的饰品。 每一回合,从中选出三块 最重的 银饰,然后一起熔掉。假设银饰的重量分别为 x 、y 和 z, 且 x <= y <= z。那么熔掉的可能结果如下: 如果x == y == z,那么三…...

糖果促销【百度之星】/思维
糖果促销 思维 大佬的解法: #include<bits/stdc.h> using namespace std; typedef long long ll; int main() {ll t;cin>>t;for(int i0;i<t;i){ll p,k;cin>>p>>k;if(k0) cout<<0<<endl;else{k-(k-1)/p;cout<<k<…...

【python学习】安装Anaconda后,如何进行环境管理(命令行操作及图形化操作Anaconda Navigator)及包管理
命令行的方式 首先,打开 Anaconda Powershell Prompt 环境查看 使用以下命令查看当前所有环境: conda env list目前只有一个 base环境,就是安装 anaconda的时候选择的。 光标在闪烁,目前已经进入 base 环境模式: …...

HTML大雪纷飞
目录 写在前面 HTML简介 完整代码 代码分析 运行结果 系列文章 写在后面 写在前面 小编又又又出现啦!这次小编给大家带来大雪纷飞HTML版,不需要任何的环境,只要有一个浏览器,就可以随时随地下一场大雪哦! HTM…...

问界新M7 Ultra仅售28.98万元起,上市即交付
5月31日,问界新M7 Ultra正式上市。发布会上,鸿蒙智行旗下多款产品交出最新答卷——问界新M5上市1个月大定突破2万台;智界S7位列30万纯电轿车4月交付量NO.3;问界M9上市5个月大定突破9万台。其中,作为中国高端豪华SUV市场…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...

视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...

华硕a豆14 Air香氛版,美学与科技的馨香融合
在快节奏的现代生活中,我们渴望一个能激发创想、愉悦感官的工作与生活伙伴,它不仅是冰冷的科技工具,更能触动我们内心深处的细腻情感。正是在这样的期许下,华硕a豆14 Air香氛版翩然而至,它以一种前所未有的方式&#x…...
【Go语言基础【13】】函数、闭包、方法
文章目录 零、概述一、函数基础1、函数基础概念2、参数传递机制3、返回值特性3.1. 多返回值3.2. 命名返回值3.3. 错误处理 二、函数类型与高阶函数1. 函数类型定义2. 高阶函数(函数作为参数、返回值) 三、匿名函数与闭包1. 匿名函数(Lambda函…...