一文学会自制python自动化工具——python实现学校健身房自动化预约(还不会写爬虫?来看这!原理秒懂喔!)

声明:本文仅供学习交流,不针对学校及个人,无意破坏竞争公平性。

最近刚看了看python文档,不出半小时必打盹,就想着用它来制作点小工具玩玩。
正好学校健身房限额预约,同学们可都真自律啊!!!定着早上六点多的闹钟抢,作为一个懒惰的健身选手,我必然是要出奇制胜。
在这个过程中,解决各式各样的问题可比单纯磕文档有效率得多。
话不多说,拿刀来:

网站信息收集与分析

该网站比较简易,几乎全是get请求,分析起来也很容易。

请求机制

完整网址就不放了,大概说一下请求机制,入口在企业微信工作台,访问时会通过微信进行登录:
因为微信内置浏览器不方便抓包,通过查看第二次的url和查询资料可以推断,
微信验证后访问使用的url
首次请求时会携带微信验证信息,响应会给你一个code,这个code是临时的一个身份验证方式,时效非常短,访问这个url,进去后随便点击一下,你的code的作用就到头了,随之而来的是把把你的身份信息绑定到另一个参数token(一个令牌,用来证明身份)上。
token

之后,这个token在有效期内就能唯一证明你的身份,非常重要!!!

身份验证机制

token作为令牌,肯定具有时效性,否则一旦被劫持,别人就能冒充你访问网站,这是非常严重的。因此,我第一时间试验了token的可维持时间,发现差不多是10分钟(隔1分钟用该token访问一下,再隔2分钟用该token访问一下…发现过了10分钟,就会提示身份验证失效)。
因此,为了每次访问都能持有有效令牌,要么,每次访问前获取新token,要么,一直保持一个token不过期
对于获取新的token,由于微信自身安全机制很强,不易获取登录状态,要想获取也可以,后面改进方案里面会提到。
因此我选择保持一个token不过期。
插一嘴:Oauth2.0 引入了 refresh token 机制,可以用来刷新access token,当token过期后,会调用刷新token接口。一般来说,refesh token的有效期比token要长(比如token:1小时,refresh token可以维持1天),当token过期如果access token 与refresh token都过期,才进行重新登录和授权。
但是,通过验证,我发现,该网站使用一旦10分钟内未用有效token访问,就会显示用户信息获取失败,并未触发refresh token机制,证明refresh这条路走不通。
那么,我们就只能不断访问,保持token的时效性。

正片开始——上代码

准备工作——实时发送短信

这部分代码可以自行去"短信宝"这个网站找。开个账号,找到开发者,代码人家都给你了,根据需求改一下就行,很方便。
其实本来打算做成邮箱提醒的,但是想了想邮箱提醒没有短信直观方便,就选择了短信。

# coding=utf-8
import urllib
import urllib.request
import hashlib

#加密
def md5(str):
    m = hashlib.md5()
    m.update(str.encode("utf8"))
    return m.hexdigest()

def send(tips):
    statusStr = {
        '0': '短信发送成功',
        '-1': '参数不全',
        '-2': '服务器空间不支持,请确认支持curl或者fsocket,联系您的空间商解决或者更换空间',
        '30': '密码错误',
        '40': '账号不存在',
        '41': '余额不足',
        '42': '账户已过期',
        '43': 'IP地址限制',
        '50': '内容含有敏感词'
    }

    smsapi = "http://api.smsbao.com/"
    # 短信平台账号(做了遮挡)
    user = 'xxxxx'
    # 短信平台密码(做了遮挡)
    password = md5('xxxxxxx')
    # 要发送的短信内容
    content = '健身房预约结果为:'+tips + '。'
    # 要发送短信的手机号码(做了遮挡)
    phone = 'xxxxxxxx'

    data = urllib.parse.urlencode({'u': user, 'p': password, 'm': phone, 'c': content})
    send_url = smsapi + 'sms?' + data
    response = urllib.request.urlopen(send_url)
    the_page = response.read().decode('utf-8')
    print(statusStr[the_page])

主力军——发送网络请求

下面展示一些 带token发送网络请求,保持token不过期

import requests
import re
import send_message
import time

def keep_token():
	# url部分遮挡了,自己改喔
    url = "https://xxx.xxx.xxx.xxx/gym/?state=1#/pages/index"	
     # 字典格式,推荐使用,它会自动帮你按照k-v拼接url
    myParams = {"token": "202xxxxx1909123888r6axxxxoqd"}   
    # 发送请求
    res = requests.get(url=url, params=myParams)
    # 如果响应码是200,也就是访问成功
    if res.status_code == 200:								
        print('Success to keep token...        '+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))	# 利用time模块获取当前时间,方便后面搞个日志功能啥的	
    # 访问不成功
    else:			
        print('Failure to keep token...        '+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
        send_message.send('token刷新异常,可能导致预约失败,请尽快查看。')		# 调用函数send,发送短信提醒。

下面展示一些 发送请求,预约指定时段的健身房

def appoint():
	# url部分遮挡了,自己改喔
    url = "http://xxx.xxxx.xxx.xxx/ccms-gym/gym/queue/appointMulti"
    #通过信息收集可知,dateId是日期id,1表示今天,2表示明天;ptId是时间段id,每个时间段对应一个id,打开网页F12就能看见。
    myParams = {"token": "202208xxxxxxx888r6xxxx2oqd", "dateId": 2, "ptId": 20,
                "areaId": 3}  
    #发送请求
    res = requests.get(url=url, params=myParams)
    #请求成功
    if res.status_code == 200:
    	#正则表达式获取响应的text里面的汉字,汉字范围为:[\u4e00-\u9fa5]
        chinese = re.findall('[\u4e00-\u9fa5]', res.text)  
        #因为获取到的汉字是存在列表里面的,所以我把它们连成字符串
        tips = ''
        for i in range(len(chinese)):
            tips = tips + chinese[i]
        #打印汉字内容+当前时间
        print (tips+'                         '+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))	
        #发送短信
        send_message.send(tips)	
    #请求失败
    else:
        print('Failure to apply...            '+time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
        send_message.send('请求失败,可能导致预约失败,请尽快查看。')

最简单但最巧妙——多线程并行执行

我是碰到问题了,一步步找解决方案,最后才搞出这个来,很简单、很实用、就是资料查的有点崩溃。。。

问题:保持token有效,就得不断访问,怎么实现?
答:循环+time.sleep()
又来问题:预约健身房要到开放系统的那个时间点才能发送请求,怎么实现?
答:定时任务,查了一下,schedule调度器太合适了。

那么前面的也可以用调度器来实现不断访问保持token有效啊。
我们选定,schedule

接着,调试代码发现,schedule实现定时任务未到约定时间自身也会阻塞,阻塞就意味着执行一个任务,另一个就没法执行。保持了token有效就不能顺利提交预约请求,要提交预约请求就不能不断访问保持token有效,显然是矛盾的。

对此,多番查询,发现了python的多线程和多进程机制。
二者的区别浅显地讲一下:多线程适用于多次执行,但计算量不大;多进程适用于计算量大,但访问次数少。(多线程总是在一个进程里进行的,对资源消耗比较友好,而多进程会占用更多的cpu资源)
显然,此处更适合使用多线程。因为设置了定时,两个任务完全可以交叉进行,完美解决单线程堵塞问题。

import schedule
import threading
import oppoint
#多线程
# 讲函数作为参数传递进去,作为一个线程函数
def run_threaded(func):
    job_thread = threading.Thread(target=func)
    job_thread.start()
# 为了维持token有效,调度器设置每9分钟执行一次,do后面的run_threaded是要执行的函数,oppoint.keep_token是要执行函数的参数
schedule.every(9).minutes.do(run_threaded, oppoint.keep_token)
# 发送预约请求,调度器设置每天6:50执行
schedule.every().day.at("06:50").do(run_threaded,oppoint.appoint)

#死循环,让程序一直运行
while True:
	#执行所有线程
    schedule.run_pending()

至此,我的自动预约健身房v1.0就完成了。

运行截图

为了测试,我将keep_token的时间改成了5秒一访问,oppoint的时间改为了7:31。
屏幕输出

收到的短信

改进方案和预期

这个小工具写的有点仓促,很多地方还不完善,提出问题及改进方案,为我的v2.0做准备。

问题改进方案
token还无法自动获取尝试appium自动化操作微信获取token(这时就可以抛弃不断访问这一步了)
程序稳定性及可用性不足尝试借助windows服务,开机自启,到点直接执行
数据修改必须在源码上进行,操作不便尝试利用Tkinter实现GUI,增加可操作性
功能单一尝试添加其他场景,包括但不限于:自动预约体育馆其他场馆、自动预约图书馆

心得体会

作为一个菜鸡,csdn逛了两年基本都是为了抄作业,咳咳,现在写出一点东西来了也算是自己小小的进步吧。

不断解决问题永远是学习的最佳路径,当然学习的目的也就是为了解决问题。

我喜欢这种做出一个东西来的同时学会了一大堆东西的感觉。可谓,成就感满满hhh。

前段时间看了看scrapy框架,写了几个小爬虫,但是对于原理了解还是不透彻。写了这个小工具后,对调度器、多线程并发、网络请求、管道(解决问题的过程中,还重新挖了挖管道的知识,虽然没用上)等都理解更深刻了。

共勉!!!

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Godchar

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值