前言
不知道大家有没有经历过寝室突然断电的情况,但作者肯定遭遇过折磨,不然不会来写这篇文章来和各位分享。代码很俗,主要是分享解题思路以及希望能帮大家脱离这个诡异的折磨。不理解学校为什么可以安装电视机专门用来提示电量却不愿意接入移动校务平台。
本项目相较于其他文章的优点在于:
1.采用的接口没有身份验证,不失效。
2.若当前请求获取电量与上一次比较没有发生变化,则不会推送消息,避免过多打扰。
3.低电量提示外,还有每日更新。
效果如下:
一、抓包电量查询接口
在抓取电量查询接口的过程中,发现了3个接口,分别如下:
一卡通服务平台https://epay.sues.edu.cn/epay/electric/queryelectricbill?sysid=4&roomNo=6006&elcarea=101&elcbuis=16
完美校园官网http://h5cloud.17wanxiao.com:8080/CloudPayment/user/getRoomState.do?
由于前两个接口都需要cookie和X-Csrf-Token验证身份,使用本项目采用的接口是第三种:http://epay.sues.edu.cn/epay/wxpage/wanxiao/eleresult?
通过抓包,我们也得到了需要提交的参数(以作者寝室为例)
sysid="4", roomid="6006", areaid="101", buildid="16"
二、获取电量信息
我们可以发现,这个接口请求返回的是一个网页,所以我们需要采用GET的方式,再用正则表达式提取出当前电量信息。
def get_eleresult(sysid, roomid, areaid, buildid):
url = 'http://epay.sues.edu.cn/epay/wxpage/wanxiao/eleresult?sysid={0}&roomid={1}&areaid={2}&buildid={3}'.format(
sysid, roomid, areaid, buildid)
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'}
response = requests.get(url=url, headers=headers)
print(response)
soup = BeautifulSoup(response.content, 'lxml')
# print(soup.prettify()) #打印网页内容
result = soup.find_all("input", class_="weui-input")
res_str = str(result)
# print(result)
res = re.findall(r'left-degree="(.+?)"', res_str)
item = ''.join(res)
res_float = float(item)
return res_float
我们通过lxml来解析请求返回的HTML,打印内容如下。
<!DOCTYPE html>
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<meta content="IE=edge" http-equiv="X-UA-Compatible"/>
<meta content="width=device-width, initial-scale=1, user-scalable=no" name="viewport"/>
<link href="/epay/css/wxpage/weui.min.css;jsessionid=9AED1EF5B69A47101B48BB61C71A8B30" rel="stylesheet" type="text/css"/>
<link href="/epay/css/wxpage/jquery-weui.min.css;jsessionid=9AED1EF5B69A47101B48BB61C71A8B30" rel="stylesheet" type="text/css"/>
<link href="/epay/css/wxpage/wxpage.css;jsessionid=9AED1EF5B69A47101B48BB61C71A8B30" rel="stylesheet" type="text/css"/>
<title>
电费查询结果
</title>
</head>
<body>
<div class="topbar">
<a href="javascript:backTo()">
<span class="back">
</span>
</a>
<p>
电费查询结果
</p>
<a href="javascript:refresh()">
<span class="refresh">
</span>
</a>
</div>
<div class="weui-cells" style="margin: 0px;">
<div class="weui-cell">
<div class="weui-cell__bd">
房间
</div>
<div>
6006
</div>
</div>
</div>
<div class="weui-cells">
<div class="weui-cell">
<div class="weui-cell__bd">
<label class="weui-label">
剩余电量
</label>
</div>
<div>
66.1度
</div>
</div>
<div class="weui-cell">
<div class="weui-cell__hd">
<label class="weui-label">
充值
</label>
</div>
<div class="weui-cell__bd">
<input class="weui-input" id="roomdef" left-degree="66.1" pattern="[0-9]*" placeholder="请输入充值金额" type="number"/>
</div>
</div>
</div>
<input id="sysid" type="hidden" value="4"/>
<input id="roomid" type="hidden" value="6006"/>
<input id="areaid" type="hidden" value="101"/>
<input id="buildid" type="hidden" value="16"/>
<a class="weui-btn weui-btn_primary btn-bg" href="javascript:doNext();" style="margin: 40px">
充值
</a>
<div id="d2" style="text-align: center">
<span>
电费充值无法退款,请酌情购电!
</span>
<br/>
<span>
节约用电,注意用电安全!
</span>
</div>
<script src="/epay/idxcss/js/jquery-3.6.0.min.js;jsessionid=9AED1EF5B69A47101B48BB61C71A8B30 " type="text/javascript">
</script>
<script src="/epay/js/wxpage/fastclick.js;jsessionid=9AED1EF5B69A47101B48BB61C71A8B30 " type="text/javascript">
</script>
<script>
$(function () {
FastClick.attach(document.body);
$.showLoading("正在加载");
var param = {}
// var data2 = null;
$.ajax("/epay/wxpage/wanxiao/getsecondText.json;jsessionid=9AED1EF5B69A47101B48BB61C71A8B30", {
data: JSON.stringify(param),
type: "POST",
contentType: "application/json",
dataType: "json",
success: function (ret) {
$.hideLoading();
if (ret.retcode == '0') {
data2 = ret.text;
} else {
data2 = null;
}
// document.getElementById("d1").innerHTML=data2;
},
error: function (e) {
$.hideLoading();
$.alert("提示语加载失败", "错误");
}
});
});
</script>
<script src="/epay/js/wxpage/jquery-weui.min.js;jsessionid=9AED1EF5B69A47101B48BB61C71A8B30 " type="text/javascript">
</script>
<script>
var data2;
function refresh() {
window.location.reload();
}
function doNext() {
var inputs = $("input[type='number']");
var arr = [];
var def = $("#roomdef").val();
var find = false;
$.each(inputs,function (index,e) {
var bean = $(e);
var code = bean.attr("id");
console.log(bean.val());
if(code!='roomdef'){
var amt = bean.val();
if(amt!=null&&amt!=''){
if(amt<=0){
$.alert("充值金额不能小于0")
return;
}
var temp = {
"elecode":code,
"dpsamt":bean.val(),
"dumpEnergy":bean.attr("left-degree")
}
arr.push(temp);
}
}
})
if(!def&&arr.length==0){
$.alert("至少充值一项")
return;
}
if(def){
if(def==null||def==""||def<=0){
$.alert("请输入正确的充值金额")
return;
}
var rest = $("roomdef").attr("left-degree");
$.showLoading("正在下单");
window.location.href='/epay/wxpage/wanxiao/elepaybill;jsessionid=9AED1EF5B69A47101B48BB61C71A8B30?sysid='+$("#sysid").val()+'&roomid='+$("#roomid").val()+'&areaid='+$("#areaid").val()+'&buildid='+$("#buildid").val()
+'&amount='+def+"&rest="+rest;
}else{
$.showLoading("正在下单");
window.location.href='/epay/wxpage/wanxiao/elepaybill;jsessionid=9AED1EF5B69A47101B48BB61C71A8B30?sysid='+$("#sysid").val()+'&roomid='+$("#roomid").val()+'&areaid='+$("#areaid").val()+'&buildid='+$("#buildid").val()
+'&dpsstr='+JSON.stringify(arr);
}
}
function backTo() {
window.history.back();
}
</script>
</body>
</html>
可以看到我们想要的数据在class="weui-input"
使用soup.find_all()查找这一行内容,得到如下:
[<input class="weui-input" id="roomdef" left-degree="66.1" pattern="[0-9]*" placeholder="请输入充值金额" type="number"/>]
再利用正则表达式将【电量】提取出来,由于re.findall返回的是list,这里需要使用join将列表中的元素拼接成字符串。
res = re.findall(r'left-degree="(.+?)"', res_str)
item = ''.join(res)
到这里我们就完成了【电量】的获取,接下来就需要将消息推送。
三、消息推送
本项目采用了wxpush平台进行消息推送,当然也可以选择pushplus等,如果不想接入第三方平台的话也可以采用邮箱推送。这里不赘述如何配置,可以搜索一下其他大佬的文章。
def wx_push(power, ID):
if power <= 15.0:
content = ("请尽快充值!剩余电量:{0}度".format(power))
else:
content = ("剩余电量:{0}度".format(power))
headers = {"content-type": "application/json"}
app_token = ''
webapi = 'https://wxpusher.zjiecode.com/api/send/message'
data = {
"appToken": app_token,
"content": content, # 主体内容
"contentType": 1, # 文本
"topicIds": [ID], # 应用列表的ID
}
result = requests.post(url=webapi, json=data, headers=headers)
return result.text
四、完整代码
#!/user/bin/env python3
# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup
import re
import time
import datetime
power: float = 0.0
before_6006: float = 0.0
power_6006: float = 0.0
yesterday: int = 0
def get_eleresult(sysid, roomid, areaid, buildid):
url = 'http://epay.sues.edu.cn/epay/wxpage/wanxiao/eleresult?sysid={0}&roomid={1}&areaid={2}&buildid={3}'.format(
sysid, roomid, areaid, buildid)
requests.packages.urllib3.disable_warnings()
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36'}
response = requests.get(url=url, headers=headers)
print(response)
soup = BeautifulSoup(response.content, 'lxml')
# print(soup.prettify()) #打印网页内容
result = soup.find_all("input", class_="weui-input")
res_str = str(result)
# print(result)
res = re.findall(r'left-degree="(.+?)"', res_str)
item = ''.join(res)
res_float = float(item)
return res_float
def wx_push(power, ID):
if power <= 15.0:
content = ("请尽快充值!剩余电量:{0}度".format(power))
else:
content = ("剩余电量:{0}度".format(power))
headers = {"content-type": "application/json"}
app_token = ''
webapi = 'https://wxpusher.zjiecode.com/api/send/message'
data = {
"appToken": app_token,
"content": content, # 主体内容
"contentType": 1, # 文本
"topicIds": [ID], # 应用列表的ID
}
result = requests.post(url=webapi, json=data, headers=headers)
return result.text
# 用户列表
def user_data(user):
if user == 6006:
power = get_eleresult(sysid="4", roomid="6006", areaid="101", buildid="16")
return power
if __name__ == '__main__':
while True:
try:
# 获取6006电量
power_6006 = user_data(6006)
# 6006每日更新
if yesterday != datetime.date.today().day:
result = wx_push(power_6006, "推送id")
yesterday = datetime.date.today().day
# 6006低电量变化提示
if before_6006 != power_6006 and power_6006 <= 5.0:
result = wx_push(power_6006, "推送id")
else:
pass
if before_6006 != power_6006:
print("{1} [更新] 6006:{0}度".format(power_6006,
time.strftime('%Y.%m.%d %H:%M:%S', time.localtime(time.time()))))
before_6006 = power_6006
except:
time.sleep(300)