---
title: 微信读书Cookies续活
layout: post
cover: 'https://upyun.thatcdn.cn/myself/typora/202309132130825.jpg'
tags: ['Tencent']
categories: ['堆栈']
poster:
headline: ''
caption: ''
color: 'white'
description: '实现微信读书的Cookies在生命结束后自动刷新'
date: 2023-09-13 19:00:00
机制分析
很多优秀的文章分析了延期机制, 这里列举两个
{% link https://zhaohongxuan.github.io/2022/05/16/how-to-relong-cookies-in-weread/ Hank's Blog 微信读书延期机制分析 %}
稳定性
目前跑了几天, Cookies都能自动刷新保活
主要代码
续活我没使用代理服务器, 直接请求了
// 刷新 Cookie 的函数,模拟发送请求获取新 Cookie
const refCookie = async (uid: string) => {
try {
const response = await axios.head('https://weread.qq.com', { headers: globalHeaders() });
if (response.status === 200 || response.headers['set-cookie']) {
globalCookies = CookieUtil.WebArrayToString(response.headers['set-cookie'], globalCookies);
return (await upUserCookie(uid)) ? true : false
}else {
return false
}
} catch (e) {
return false
}
}
全部代码
运行在自己搭建的 Laf 云函数, 不能无脑抄。 代码虽烂 但已写注释。
需要临时使用我的接口可以联系我
{% folding 代码结构图 %}
{% image https://upyun.thatcdn.cn/myself/typora/202309132103742.png 这样也许清晰一点 ratio:1689/1282 %}
import axios from 'axios';
import cloud from "@/cloud-sdk";
/**
* API请求入口方法
*/
exports.main = async function (ctx: FunctionContext) {
try {
const { cookies, uid, refresh } = ctx.method === 'GET' ? ctx.query || ctx.params : ctx.body;
if (verifyData(uid)) { // 用户获取cookie请求
if ((await userServer.verifyUser(uid))) {
!(await CookiesApi.verifyRefresh(uid)) || (await CookiesApi.refCookie(refresh))
return msgServer.success("获取Cookie成功", { cookies: globalCookies })
} else {
return msgServer.failed("搞咩! " + uid + " 不存在!");
}
} else if (verifyData(cookies)) { // 新增用户请求
const uid = CookieUtil.StringToJson(cookies)['wr_vid']
globalCookies = cookies
const userInfo = (await CookiesApi.getUserInfo(uid))
if (!userInfo['name']) {
return msgServer.failed("搞咩! cookies 不能用!");
}
const userData: WxReadUser = {
'userVid': uid,
'userInfo': userInfo,
'cookies': globalCookies,
'cookies_uptime': (new Date()).valueOf(),
'cookies_life': true
}
const add = (await userServer.addUser(userData))
if (add.answer) {
return msgServer.success(
`存入cookies成功, 未来取用cookies请通过以下方式${'\n'}[ https://sijnzx.laf.thatcoder.cn/tencent-weread-refcookie?uid=您的userVid ]`,
{ userVid: uid, userInfo }
)
} else {
return msgServer.error()
}
} else if (verifyData(refresh)) { // 刷新请求
let req: any
if (!(await CookiesApi.verifyRefresh(refresh))) {
return msgServer.success("Cookie不需要刷新")
} else {
return (await CookiesApi.refCookie(refresh)) ? msgServer.success("刷新Cookie成功") : msgServer.error()
}
} else {
return msgServer.failed("搞咩! 传的什么狗屁参数!");
}
} catch (error) {
return msgServer.error()
}
};
/**
* 获取数据库访问器
*/
const db = cloud.database().collection('tc_tencent_wxread');
/**
* cookies格式工具
*/
const CookieUtil = {
StringToJson: (cookiesString: string) => {
const cookieGroup = cookiesString.split('; ')
const cookieJson = {}
for (let i = 0; i < cookieGroup.length; i++) {
const cookieGroupJson = cookieGroup[i].split('=')
cookieJson[cookieGroupJson[0]] = cookieGroupJson.length === 1 ? '' : cookieGroupJson[1]
}
return cookieJson
},
JsonToString: (cookiesJson: object) => {
const keyValuePairs = [];
for (const key in cookiesJson) {
if (cookiesJson.hasOwnProperty(key)) {
const value = cookiesJson[key];
keyValuePairs.push(`${key}=${value}`);
}
}
return keyValuePairs.join('; ');
},
WebArrayToString: (cookiesArray: Array<string>, cookiesString: string) => {
let cookieJson = CookieUtil.StringToJson(cookiesString)
for (const cookie of cookiesArray) {
const refresh: Array<string> = cookie.split('; ')[0].split('=')
cookieJson[refresh[0]] = refresh[1]
}
return CookieUtil.JsonToString(cookieJson)
},
StringToArray: (cookiesString: string) => {
return cookiesString.split('; ')
}
}
// 全局变量。不合理, 但是能减少云函数单文件代码量
var globalCookies = ""
var globalHeaders = () => {
return {
Cookie: CookieUtil.StringToArray(globalCookies), // 传入的 Cookie 数组
Referer: 'https://weread.qq.com/',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*',
}
}
/**
* 微信读书API方法
*/
const CookiesApi = {
/**
* 获取用户信息
* @uid: 微信Cookie['wr_vid']
*/
getUserInfo: async (uid: string) => {
let userInfo = { 'userVid': "" }
await axios.get('https://weread.qq.com/web/user?userVid=' + uid, { headers: globalHeaders() }).then(e => {
userInfo = e.data
})
return userInfo
},
/**
* 验证Cookie是否存活
* @uid: 微信Cookie['wr_vid']
*/
verifyAlive: async (uid: string) => {
const cookie = (await userServer.getUserCookie(uid))
globalCookies = cookie
let userInfo = await CookiesApi.getUserInfo(uid)
return (String)(userInfo['userVid']).includes(uid)
},
// 判断是否需要刷新 Cookie
verifyRefresh: async (uid: string) => {
const time = (await userServer.getUserCookieTime(uid))
if ( !(await CookiesApi.verifyAlive(uid)) || (new Date()).valueOf() - time >= 3600000) {
return true
}
return false
},
// 刷新 Cookie 的函数,模拟发送请求获取新 Cookie
refCookie: async (uid: string) => {
try {
const response = await axios.head('https://weread.qq.com', { headers: globalHeaders() });
// if (response.status === 200) {
// return true
// }
const newCookies = response.headers['set-cookie']
if (!newCookies) {
return false
}
globalCookies = CookieUtil.WebArrayToString(newCookies, globalCookies);
return (await userServer.upUserCookie(uid)) ? true : false
} catch (e) {
return false
}
}
}
/**
* 数据库服务层。 呵, JS哪来的服务层
*/
const userServer = {
/**
* 验证数据库是否存在用户
* @uid: 微信Cookie['wr_vid']
* @return: {boolean}
*/
verifyUser: async (uid: string) => {
return (await db.where({ 'userVid': uid }).count()).total > 0
},
/**
* 获取用户Cookie
* @uid: 微信Cookie['wr_vid']
*/
getUserCookie: async (uid: string) => {
const get = (await db.where({ 'userVid': uid }).limit(1).get())
return get.data[0]['cookies']
},
/**
* 获取用户CookieTime
* @uid: 微信Cookie['wr_vid']
*/
getUserCookieTime: async (uid: string) => {
const get = (await db.where({ 'userVid': uid }).limit(1).get())
return get.data[0]['cookies_uptime']
},
/**
* 更新用户Cookie
*/
upUserCookie: async (uid: string) => {
return (await db.where({'userVid': uid}).limit(1).update({ cookies: globalCookies, cookies_uptime: (new Date()).valueOf(), cookies_life: true })).ok
},
/**
* 新增数据库用户信息
*/
addUser: async (userData: WxReadUser) => {
let add: any
if ((await userServer.verifyUser(userData.userVid))) {
add = (await db.where({'userVid': userData.userVid}).limit(1).update(userData))
} else {
add = (await db.add(userData))
}
return { answer: add.ok, id: add.upsertId }
}
}
/**
* 回执服务层
*/
const msgServer = {
success: (msg: string, data: any = {}) => {
return JSON.stringify({ statusCode: 200, event: "操作成功", message: msg, data })
},
failed: (msg: string) => {
return JSON.stringify({ statusCode: 400, event: "操作失败", message: msg })
},
error: () => {
return JSON.stringify({ statusCode: 500, event: "程序错误", message: "请联系钟意, 必应搜索钟意博客。" })
}
}
/**
* 微信用户对象接口
*/
interface WxReadUser {
'userVid': string,
'userInfo'?: any,
'cookies': string,
'cookies_uptime'?: number,
'cookies_life'?: boolean
}
const verifyData = (data: any) => {
if (data === null || data === [] || data === {} || data === undefined || data === '') {
return false
} else if (data.length > 0) {
return true
} else {
return false
}
}
实际应用
- 获取自己的微信读书信息
- 下载微信读书的书籍
- 导出书单信息
- 带出读书笔记
- 自动阅读( 这个功能有什么用? )
浙公网安备 33010602011771号