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个元素,如下图所示。

  随后,查看这个元素的信息,如下图所示。可以看到,这是1POST请求,具体的请求Headers也是比较常规的。

  这里提一句,我一开始看到这个POST请求的Headers具有伪头部(也就是上图中右下角紫色框内,排在前4个的、Key前带有冒号:的头部),说明其是HTTP/2的请求;所以当时还以为不能用Pythonrequests库了,然后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个人可以注册多个域名,不同域名的邮箱之间就可以互发邮件)——其中一个作为发件地址,另一个作为收件地址

  我们如果此时执行上述代码,即可看到指定日期内体检名额的剩余情况。其中,如下图所示,某次执行后,发现0603日这一天有体检的名额了(原本写代码时0603日还是没有名额的,这说明有1位同学预约了这一天但是现在取消了)。

  那么,邮箱中就会收到如下图所示的提醒邮件。如果大家开启了类似微信的邮件实时提醒,或手机端邮箱APP应用消息通知,那么相当于就是实时接收体检余额的提醒了。

  为了方便,我们也将体检预约的网页链接放在了邮件中,如下图所示;点击后即可进入预约。

  进入预约网页内,发现果然0603日这一天,当前是可以预约的。如果有需要的话,此时就可以手动预约了。

  当然,上述我们是单次执行程序。如果希望可以在后台定时对体检余额加以检测(例如我想每隔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分钟运行1run_script()函数,而这个函数就是用来执行本文前述的那一段监测余量发送邮件的代码——也就是上述代码中的check.py文件;这里因为我将2Python代码文件放在同一路径下了,所以就用了相对路径。

  随后,通过手动调用1run_script()函数,使得程序开始时先执行1次查询,然后再每隔30分钟查询1次。代码最后,进入1个无限循环,并在循环中调用schedule.run_pending()函数,确保按预定计划运行run_script()函数;同时,在每1次循环中,脚本会休眠1秒钟,避免占用太多CPU资源。

  完成上述代码后,执行这一文件,即可看到已经按照要求,每隔30分钟查询1次体检余量了。

  如果查询过程中,发现指定日期出现了体检名额,那么和本文前述内容一样,程序会自动给我们发邮件,提醒我们可以预约了。这里大家可以结合自己的使用场景与个人需求,修改每次查询的间隔时间;但是建议不要间隔的时间太短,否则可能会被网站的服务器屏蔽。

  当然,还是那句话,本文这里的代码只能自动监控余量并加以邮件提醒,而没有实现发现余量后自动预约。如果大家感兴趣,可以进一步实现自动预约的需求。

  至此,大功告成。

欢迎关注:疯狂学习GIS

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/20538.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Day44 动态规划part04

背包问题 01背包问题:每件物品只能用一次完全背包问题:每件物品可以使用无数次 01背包问题 暴力解法:每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是 o…

Transformer从0到1的学习【还有2-10,别想太多】

1.高纬度介绍Transformer 1.分为编码Encoders和解码器Decoders:“我爱你”作为编码器Encoders的输入进行编码得到序列码后,作为解码器的输入得到输出即为,“I Love you”。 2.编码器和译码器的具体拆分: 左边的编码器Encoders的…

【常见的六大排序算法】插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序

个人主页 创作不易,感谢大家的关注! 文章目录 前言 🎡一、插入排序🌲二、希尔排序🎉三、选择排序🎀四、冒泡排序🚘五、堆排序🛵六、快速排序1. Hoare版本2. 挖坑法3. 前后指针法4. 非…

大佬推荐的好用网盘工具

转载说明:如果您喜欢这篇文章并打算转载它,请私信作者取得授权。感谢您喜爱本文,请文明转载,谢谢。 前段时间有大佬推荐了一款网盘工具seafile,自己搭建起来试用了一下,发现还挺好用的,这款工具…

【C++】C++11新特性:新的类功能、可变参数模板、STL容器中的empalce相关接口函数、lambda表达式、包装器(function、bind)

目录 一、新的类功能 1.1 移动构造函数和移动赋值运算符重载 1.2 强制生成默认函数的关键字default 1.3 禁止生成默认函数的关键字delete 1.4 其它的类功能 二、可变参数模板 三、STL容器中的empalce相关接口函数 四、lambda表达式 4.1 lambda的引入 4.2 lambda表达式…

openVPN+SmartDNS=openDNS or smartVPN?

正文共:777 字 11 图,预估阅读时间:1 分钟 我们现在已经熟练的掌握了openVPN的部署方式和配置方法(带认证的openVPN连接/断开操作指南),还掌握了在CentOS系统部署SmartDNS的方法(基于CentOS部署…

【网络安全】Web安全基础 - 第二节:前置基础知识- HTTP协议,握手协议,Cookie及Session

本章节主要介绍一些基础知识 d(^_^o) HTTP协议 什么是HTTP 超文本传输协议(HyperText Transfer Protocol)是一种用于分布式、协作式和超媒体信息系统的应用层协议。 HTTP是一个基于请求与响应,无状态的,应用层协议,…

100.网络游戏逆向分析与漏洞攻防-ui界面的设计-聊天功能的界面与设计

免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 如果看不懂、不知道现在做的什么,那就跟着做完看效果 现在的代码都是依据数据包来写的,如果看不懂代码,就说明没看懂数据包…

Git常用命令1

1、设置用户签名 ①基本语法: git config --global user.name 用户名 git config --global user.email 邮箱 ②实际操作 ③查询是否设置成功 cat ~/.gitconfig 注:签名的作用是区分不同操作者身份。用户的签名信息在每一个版本的提交…

MulterError: Field name missing 报错解决

Request POST /FileUpload/chunkApi/upload/mProjectNews/Images failed with status code 500. MulterError: Field name missing. 原因:Multer是基于Busboy解析的表单参数信息,经定位发现是解析表单中文本参数时出现了null,故收到MISSION_…

【算法】模拟算法——数青蛙(medium)

题解:模拟算法——数青蛙(medium) 目录 1.题目2.题解3.参考代码4.总结 1.题目 题目链接:LINK 2.题解 用循环进行遍历, 如果该字符为o\o\a\k 找一下前驱字符是否存在 如果存在,前驱字符–,该字符如果不存在&#x…

CATIA二次开发VBA入门(4)——进程外开发环境搭建,vb.net在Visual Studio中开发,创建圆柱曲面的宏录制到二次开发案例

目录 引出vb.net和vb6.0 进程外开发环境搭建vb.net开发环境搭建《CATIA二次开发技术基础》模板 添加宏库引用 vs开发环境初步vs中的立即窗口对象浏览器 建立模板案例:创建一堆圆柱曲面第一步:录制宏第二步:代码精简第三步:for循环…

⌈ 传知代码 ⌋ 命名实体识别

💛前情提要💛 本文是传知代码平台中的相关前沿知识与技术的分享~ 接下来我们即将进入一个全新的空间,对技术有一个全新的视角~ 本文所涉及所有资源均在传知代码平台可获取 以下的内容一定会让你对AI 赋能时代有一个颠覆性的认识哦&#x…

提升B端图表设计技能:教程分享

图表是数据可视化的常用表现形式,是对数据的二次加工,可以帮助我们理解数据、洞悉数据背后的真相,让我们更好地适应这个数据驱动的世界。本期就来带大家学习图表的设计及构成,帮助大家更好的理解图表设计。 设计教程源文件http:/…

OpenAI已全面开放自定义GPT以及文件上传等功能

今天,OpenAI兑现了前段时间做出的承诺:免费向所有用户开放GPT-4o。这意味着所有的免费用户都能使用自定义GPT模型、分析图表等其他GPT-4o新功能了。现在ChatGPT界面长这样: 可以看出,免费用户也能使用GPT store中定义好的模型&…

Python开发与应用实验1 | 开发环境安装配置

*本文来自博主对专业课 Python开发与应用 实验部分的整理与解析。 *一些题目可能会增加了拓展部分(⭐)。拓展部分不是实验报告中原有的内容,而是博主本人的补充,以便各位学习参考。 *实验环境为:Python 3.10 &#xf…

java实现地形dem产汇流流场数据提取解析

一、基础概念 在GIS和气象学、海洋学、大气科学、水文学等领域,"提取流场"通常指的是从数据集中识别和分析流体(如水流、风场、洋流、大气流)的运动模式和流向的过程。这个过程涉及数据处理、可视化和分析技术,下面是提…

Wpf 使用 Prism 实战开发Day31

登录数据绑定 1.首先在LoginViewModel 登录逻辑处理类中&#xff0c;创建登录要绑定属性和命令 public class LoginViewModel : BindableBase, IDialogAware {public LoginViewModel(){ExecuteCommand new DelegateCommand<string>(Execure);}public string Title { ge…

vue-标签选择

效果 选中后 代码 <span :class"[item.bealtrue?p_yx_span span_active :span p_yx]" click"onTagSelect(index)" v-for"(item,index) in tagList" :key"index" >{{item.name}} </span> // 列表值 tagList:[ {id: 1, na…

R语言ggplot2包绘制世界地图

数据和代码获取&#xff1a;请查看主页个人信息&#xff01;&#xff01;&#xff01; 1. 数据读取与处理 首先&#xff0c;从CSV文件中读取数据&#xff0c;并计算各国每日收入的平均签证成本。 library(tidyverse) ​ df <- read_csv("df.csv") %>% group_…