node版自动续签进京证
适用场景
代码极其简单,主要是提供思路,需要使用的同学请具备以下条件:
- 有办理进京证需求(避免公共资源浪费)
- 会执行node代码,另外会定时任务更好(有node环境会执行即可)
- 手机APP抓包(接口地址跟参数隐藏了,需要自己抓包,不会也没关系)
此版本用于6环外无限自动续签。
注释:jjzzl 01 6环内进京证 02 6环外进京证
6环内建议手动修改,手动执行,毕竟次数宝贵
注释:jjzzl 01 6环内进京证 02 6环外进京证
代码&运行部署
node版脚本代码,可以使用青龙面板定时运行脚本任务,或者可以自己电脑安装个定时跑脚本的工具,也可以手动运行。
- 自行复制提取,关键信息自己填一下
- header上的Authorization需要自己登录抓包拿到
- 其他信息都已预置
源码
// 这里使用的青龙面板引入依赖了axios,纯净版可自行XMLHttpRequest
const axios = require('axios');
function jjz() {
// 初始地址,防止恶意访问,请求地址不提供,需要的自行抓包
const url = "jjz.jtgl.beijing.gov.cn";
// 查询状态接口
const self = {};
self.state_url = `https://${url}/pro/applyRecordController/stateList`;
// 办理续签接口
self.inster_apply_record_url = `https://${url}/pro/applyRecordController/insertApplyRecord`;
// 访问凭证,通过抓包在请求头信息 Authorization 字段
self.auth = "";
// 续签接口数据只展示部分说明,其他的需要自行抓包研究
// 车主姓名
const user_name = "";
// 车主身份证号
const id_num = "";
// 车牌号
const plate_num = "";
// 进京地址
const address = "";
const tomorrow = new Date(new Date().getTime() + 24*60*60*1000).toISOString().slice(0, 10);
// jjzzl 01 6环内进京证 02 6环外进京证
const payload = {
"sqdzgdjd":"116.416427",
"txrxx":[],
"hpzl":"02",
"applyIdOld":"",
"sqdzgdwd":"40.038301",
"jjmdmc":"自驾旅游,其它",
"jsrxm" : user_name,
"jszh" : id_num,
"jjdq":"011",
"jjmd":"01,06",
"sqdzbdjd":"116.422833",
"sqdzbdwd":"40.044525",
"jjzzl":"02",
"jjlk":"00401",
"hphm" : plate_num,
"vId":"",
"jjrq" : tomorrow,
"jjlkmc":"京藏高速",
"xxdz" : address
};
const headers = {
"Authorization": self.auth,
"Content-Type": "application/json"
};
self.getRemainingTime = async function(self) {
const resp = await axios.post(self.state_url, {}, {
headers: headers
});
const state_result_json = resp.data;
const status_code = state_result_json["code"];
const msg = state_result_json["msg"];
let current_state = '';
let validity_period = '';
let apply_id_old = '';
if (status_code != 200) {
console.log(`状态码不等于200,接口异常,状态码:${status_code},错误信息:${msg}`);
}
// 已经申请续签后,会有字段的数据显示审核通过(待生效)、以及最新的截止日期
if (state_result_json.data.bzclxx[0]["ecbzxx"].length > 0) {
current_state = state_result_json["data"]["bzclxx"][0]["ecbzxx"][0]["blztmc"];
validity_period = state_result_json["data"]["bzclxx"][0]["ecbzxx"][0]["yxqz"];
}
else {
current_state = state_result_json["data"]["bzclxx"][0]["bzxx"][0]["blztmc"];
validity_period = state_result_json["data"]["bzclxx"][0]["bzxx"][0]["yxqz"];
}
apply_id_old = state_result_json["data"]["bzclxx"][0]["bzxx"][0]["applyId"]
return { current_state, validity_period, apply_id_old }
};
self.autoRenew = async function(self, payload) {
const resp = await axios.post(self.inster_apply_record_url, payload, {
headers: headers
});
const renew_result_json = resp.data
status_code = renew_result_json["code"];
msg = renew_result_json["msg"];
console.log(`续签接口状态码:${status_code}`);
console.log(`续签接口响应消息:${msg}`);
}
async function main(self, payload) {
const { current_state, validity_period, apply_id_old } = await self.getRemainingTime(self);
payload["applyIdOld"] = apply_id_old;
payload = JSON.parse(JSON.stringify(payload));
console.log(current_state)
console.log(validity_period)
if (current_state == "审核通过(生效中)") {
today = new Date().toISOString().slice(0, 10);
if (validity_period == today) {
console.log("剩余时间小于1天,执行续签");
self.autoRenew(self, payload);
} else {
console.log(`剩余时间大于1天,无法续签,到期时间:${validity_period}`);
}
} else if (current_state == "审核通过(待生效)"){
console.log("审核通过(待生效),无需重新申请");
} else {
self.autoRenew(self, payload);
}
}
main(self, payload)
}
jjz();
Scriptable实现iPhone小组件(进京证信息小组件)
效果预览图
未做样式优化,可自行美化,具体API详细见文档
使用步骤:
- iphone下载scriptable,appstore下载即可
- 进入软件后,右上角➕增加下面的源码,运行即可
- 手机桌面上添加scriptable组件,长按编辑组件选择你新增的代码的组件即可
- 具体API可参考官方文档
官方文档:docs.scriptable.app/request/
Scriptable版本源码
源码自行copy,Authorization自行抓包获取
// 背景图片,可自定义
const imgUrl = ''
const widgetUrl = "https://gpt.yqdsw.top/#/ai/home" // 点击小组件跳转URL
const req = await new Request(imgUrl)
// 全局字体颜色
const fontColor = Color.white()
const dummyFont = Font.boldRoundedSystemFont(14)
const daysTextFONT = Font.boldRoundedSystemFont(16) //new Font("Chalkduster", 65)
const img = await req.loadImage()
const w = await createWidget()
const widget = w
// 设置边距(上,左,下,右)
// 上下间距
const padding = { top: 0, left: 0, bottom: 0, right: 0 }
widget.setPadding(padding.top, padding.left, padding.bottom, padding.right)
Script.setWidget(widget)
Script.complete()
w.presentMedium()
async function createWidget() {
let daysText, dummyText, row, row2
const widget = new ListWidget()
widget.url = widgetUrl;
widget.backgroundImage = img;
const url = "jjz.jtgl.beijing.gov.cn";
const result = await get({ url: `https://${url}/pro/applyRecordController/stateList` })
const state_result_json = result
let current_state = ''
let title = ''
let validity_period = ''
// 已经申请续签后,会有字段的数据显示审核通过(待生效)、以及最新的截止日期
if (state_result_json.data.bzclxx[0]["ecbzxx"].length > 0) {
current_state = state_result_json["data"]["bzclxx"][0]["ecbzxx"][0]["blztmc"];
title = state_result_json["data"]["bzclxx"][0]["ecbzxx"][0]["jjzzlmc"];
validity_period = state_result_json["data"]["bzclxx"][0]["ecbzxx"][0]["yxqs"] + '到' + state_result_json["data"]["bzclxx"][0]["ecbzxx"][0]["yxqz"];
}
else {
current_state = state_result_json["data"]["bzclxx"][0]["bzxx"][0]["blztmc"];
title = state_result_json["data"]["bzclxx"][0]["bzxx"][0]["jjzzlmc"];
validity_period = state_result_json["data"]["bzclxx"][0]["bzxx"][0]["yxqs"] + '到' + state_result_json["data"]["bzclxx"][0]["bzxx"][0]["yxqz"];
}
widget.addSpacer(10)
row = widget.addStack()
row.layoutHorizontally()
row.centerAlignContent()
row.size = new Size(190, 20)
row.addSpacer()
daysText = row.addText(title)
daysText.textColor = fontColor
daysText.font = daysTextFONT
row.addSpacer()
row1 = widget.addStack()
row1.layoutHorizontally()
row1.centerAlignContent()
row1.size = new Size(190, 20)
row1.addSpacer()
daysText = row1.addText(current_state)
daysText.textColor = fontColor
daysText.font = daysTextFONT
row1.addSpacer()
row2 = widget.addStack()
row2.layoutHorizontally()
row2.centerAlignContent()
row2.size = new Size(240, 20)
row2.addSpacer()
dummyText = row2.addText(validity_period)
dummyText.textColor = fontColor
dummyText.font = dummyFont
row2.addSpacer()
return widget
}
async function get(opts) {
const request = new Request(opts.url)
request.method = 'POST'
// Authorization自行抓包获取
request.headers = {
"Authorization": "",
"Content-Type": "application/json"
}
request.body = {}
var result = await request.loadJSON()
console.log(result)
return result
}
后续
想手机上执行代码的话
可将上面node版本的调用续签的代码,自行改写成scriptable new request请求的方式,其他语法基本都一致。上面的代码只获取了信息。
参考链接
python版本的参考文章:zhuanlan.zhihu.com/p/631854961
Scriptable 脚本合集: github.com/Nicolasking…