折腾青年大学习自动观看截图的小工具

使用抓包软件 Fiddler 在微信 PC 端进行抓包,在主机名为api.lngqt.shechem.cn的请求中可以找到形如Cookie: BDed_HeaderKey=X2xQAy1bWnsNayB9YxxxxxxCF5%2FW3N%2FNBR5CWxxxxxxUFw%3D的 Cookie,它的时长还挺长的,主要是模拟微信登录过于麻烦;

编写服务端代码

在这里由于是要获取到积分界面的截图,我最初是有两个方案:

  1. 使用一张固定的手机截屏,将最新的一期的文字和积分抹去,通过爬虫获取到数据之后,对图片做一次处理;这样的话,感觉图片有点假,字体和布局都需要很麻烦去寻找测量,拒绝;

  2. 把请求的H5界面保存下来,然后通过抓包的方式使用代理,或者自建后端,总之把数据填充进去,也就是一个偷天换日的方法,看起来挺傻X的,但是好用是好用;

静态文件

在抓包时,找到http://websecond.lngqt.shechem.cn/index对应的返回数据,并将其保存为.html 扩展名文件,且把内部应用的静态文件也一并保存,放入后端中;

  • chunk-vendors.js
  • integral.js,这个积分。。(除非我们忍不住)

使用koa 作为后端,配合插件koa-static加载静态文件:

1
app.use(serve(__dirname + '/../static'));

请求头

请求头中的User-Agent一定要保持一致,否则会导致请求重定向;

1
2
3
4
5
6
7
8
9
10
11
const headers = {
"Accept": "application/json, text/plain, */*",
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 NetType/WIFI MicroMessenger/7.0.20.1781(0x6700143B) WindowsWechat(0x6304051b)",
"Content-Type": "application/x-www-form-urlencoded",
"Origin": "http://websecond.lngqt.shechem.cn",
"X-Requested-With": "com.tencent.mm",
"Referer": "http://websecond.lngqt.shechem.cn/",
"Accept-Encoding": "gzip, deflate",
"Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7",
"Cookie": "BDed_HeaderKey=X2xQAy1bWnsNayB9YxxxxxxCF5%2FW3N%2FNBR5CWxxxxxxUFw%3D"
}

后端路由

对于实现观看大学习添加记录和拿到截图界面的数据,需要三个API接口,分别对应三个路由:

1
2
3
4
5
6
7
8
9
10
11
12
router.post("/webapi/learn/learnlog", async (ctx) => {
let res = await axios.post(url + '/webapi/learn/learnlog', {
'page[page]': 1
}, { headers })
ctx.body = res.data
})
router.post("/user/user/find", async (ctx) => {
let res = await axios.post(url + '/user/user/find', {
"token": ""
}, { headers })
ctx.body = res.data
})

第一个为获取观看记录,其二是获取用户的信息,直接做一层获取转发即可;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
router.get("/webapi/learn/addlearnlog", async (ctx) => {
let { data } = await axios.post(url + '/webapi/learn/getnowlearn', {
"token": ""
}, { headers })
let now = data.data.id
let res2 = await axios.post(url + '/webapi/learn/addlearnlog', {
"token": "",
"lid": now
}, { headers })
ctx.body = {
result: 0,
data: {
id: now
}
}
})

第三个为最重要的添加观看记录的接口,需要获取到最新的待观看的大学习的 id ,然后将其作为参数请求添加记录的接口;

第四个接口是方便机器人调用的所做的,使用puppeteer库的无头浏览器加载静态的H5文件返回截图的 base64 结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
router.get("/webapi/learn/show", async (ctx) => {
const { query } = ctx
const browser = await puppeteer.launch();
const page = await browser.newPage();

await page.goto('http://127.0.0.1:3000/');
page.setViewport({
width: 375,
height: 667,
isMobile: true
})

setTimeout(async () => {
await page.screenshot({ path: '../static/img/pic.png'});
}, 2000)

let data = fs.readFileSync('../static/img/pic.png');
data = Buffer.from(data).toString('base64');
ctx.body = {
img: data
}
})

安卓端获取图片

除了在服务器上部署,我还想在旧手机上跑起来,而无头浏览器方案折腾了半天也没搞定,于是乎转变思路,简单粗暴,直接截图;

服务端代码

1
2
3
4
5
6
7
8
9
10
11
router.get("/webapi/learn/show", async (ctx) => {
shelljs.exec(`termux-notification -i 7 -t '青年大学习' -c '最新一期' --button1 '按钮'`)
shelljs.exec(`mv /sdcard/Pictures/pic.png /data/data/com.termux/files/home/big-study/static/img/pic.png`)

let data = fs.readFileSync(__dirname + '/../static/img/pic.png');
data = Buffer.from(data).toString('base64');
ctx.body = {
img: data,
log: "通知已显示"
}
})

这边利用 Termux 以及 Termux:API 调用 Android 的通知,以触发Tasker上对应的任务,任务完毕后会留下截图,再把截图移动到指定的位置;

Tasker 配置

  • 配置文件中,对事件 ->通知进行监听,设置监听标题为上述代码中的青年大学习,并选择程序为Termux:API
  • 编辑任务,需要安装插件Notification Listener(可选),文字开头着对应Tasker内的操作译名:
    • 【插件】:在该插件中删除用于触发的通知,删除的依据可选标题或者应用名;
    • 【发送意图】:操作选择android.intent.action.VIEW,类别默认即可,Mime选择text/plain,数据填写后端返回的H5页面地址http://127.0.0.1:3000
    • 【等待】:酌情延时 2 ~ 4 秒,选择操作 -> 等待;
    • 【截图】:设置对应的目录为Pictures/pic.png
    • 【关闭应用】:关闭默认打开页面的浏览器;

在Tasker进行截图时,会弹出屏幕录制的权限确认框,可以使用操作【取消对话框】,或者使用 ADB 操作,永久授予录屏权限:

1
adb shell appops set net.dinglisch.android.taskerm PROJECT_MEDIA allow

上述提到的软件都可以在我的云盘进行下载,Here

完整的代码可在我的代码仓库进行查看,Here;如果对上述蜜汁操作有更好的见地,欢迎留言评论!