提示说:答案存储于数据包中,需通过代码依次向每个接口发起请求,获取接口返回的数组,并对这些数组中的元素进行求和运算
意思就是把每一页下方的这些数字通过代码进行获取在进行相加最后的总数就是答案
方法一、
抓包加逆向一步步解析过程

抓包发现sign和_ts这个两个关键词,sign是被加密过的,这个_ts暂时还不知道是什么得看了它的js代码才知道是什么
刷新一下页面
抓住所有的包在进行搜索sign这个关键词 (搜索这个工具点击一下左键点击一下下面在ctrl+f,这个这个搜索工具就能出来)

上面的直接忽略直接看.js这个文件
在这个文件搜索一下sign这个关键词

找到了这个关键词,得分析一下js代码了,我们直接问AI叫AI分析一下什么代码什么意思
上面的代码就不用分析从function这个定义的函数开始
复制给AI
代码功能概述
这段JavaScript代码定义了一个名为loadPage的函数,用于异步加载分页数据。通过生成加密签名、构造请求参数并调用API接口,最终将返回的数据更新到页面内容中。
代码逐段解析
函数定义与时间戳生成
function loadPage(pageNumber) {
const timestamp = new Date().getTime()
- loadPage函数接收一个pageNumber参数,表示要加载的页码。
- new Date().getTime()获取当前时间戳,用于后续签名生成和请求参数。
签名生成
window.token = window.md5("tuling" + timestamp + pageNumber)
- 使用MD5算法生成签名,拼接字符串"tuling"、时间戳和页码作为输入。
- 签名结果存储在window.token全局变量中,可能用于其他逻辑。
构造请求参数
const params = {
page: pageNumber,
sign: window.token,
_ts: timestamp,
};
const queryString = new URLSearchParams(params).toString();
- 将页码、签名和时间戳组成参数对象。
- URLSearchParams将对象转换为URL查询字符串格式(如?page=1&sign=xxx&_ts=123)。
发起API请求
fetch(`/api/problem-detail/${problemId}/data/?${queryString}`)
- 使用Fetch API发起GET请求,目标URL包含:
- 基础路径/api/problem-detail/${problemId}/data/(其中problemId应为外部变量)
- 查询字符串参数。
处理响应数据
.then(response => response.json())
.then(data => updatePageContent(data))
.catch(error => console.error('Error fetching problem details:', error));
}
- 第一个.then将响应解析为JSON格式。
- 第二个.then调用updatePageContent函数(假设已定义)处理返回的数据。
- .catch捕获并打印网络请求或数据处理中的错误。
关键点说明
以上就是AI解释的意思
我们打断点看看他代码的运行过程
刷新一下它,它就会断在你打的断点

就像这样,它代码运行到你打的断点这,就不会运行下去

图片可以看出,它各部分的值是怎么形成的

_ts:现在看出来这个东西是啥东西了
这个东西就相当于一个时间戳

一样不懂就问AI
解释代码含义
const timestamp = new Date().getTime() 这段代码用于获取当前时间的时间戳(毫秒数)。
- new Date() 创建一个表示当前时间的 Date 对象。
- .getTime() 是 Date 对象的方法,返回从 1970 年 1 月 1 日 00:00:00 UTC 到当前时间的毫秒数(即 Unix 时间戳)。
返回值类型
该代码返回一个数值(number 类型),表示当前时间距离 Unix 纪元(1970-01-01 00:00:00 UTC)的毫秒数。例如:
console.log(timestamp); // 输出类似 1625097600000 的数字
常见用途
时间戳常用于以下场景:
- 记录事件发生的精确时间
- 计算时间间隔(如性能测量)
- 生成唯一标识(结合随机数)
- 作为缓存键名避免重复
等效写法
JavaScript 中获取时间戳的其他方式:
const timestamp = Date.now(); // 更简洁的写法
const timestamp = +new Date(); // 通过一元运算符转换
注意事项
- 时间戳是毫秒级精度(而非秒级),某些系统可能需要除以 1000 转换为秒。
- 不同时区的客户端会生成相同的 UTC 时间戳。
- 最大安全值为 8640000000000000,超过会导致错误。
sign这个关键词我们看一下图片,它的加密过程是怎样的
我们就把代码拷贝下来,新建一个js文件
JS代码如下
window = this, function (n) {
function r(n, r) {
var t = (65535 & n) + (65535 & r);
return (n >> 16) + (r >> 16) + (t >> 16) << 16 | 65535 & t
}
function t(n, t, o, u, e, c) {
return r(function (n, r) {
return n << e | n >>> 32 – e
}(r(r(t, n), r(u, c))), o)
}
function o(n, r, o, u, e, c, f) {
return t(r & o | ~r & u, n, r, e, c, f)
}
function u(n, r, o, u, e, c, f) {
return t(r & u | o & ~u, n, r, e, c, f)
}
function e(n, r, o, u, e, c, f) {
return t(r ^ o ^ u, n, r, e, c, f)
}
function c(n, r, o, u, e, c, f) {
return t(o ^ (r | ~u), n, r, e, c, f)
}
function f(n, t) {
var f, i, a, h, g;
n[t >> 5] |= 128 << t % 32, n[14 + (t + 64 >>> 9 << 4)] = t;
var l = 1732584193, d = -271733879, v = -1732584194, C = 271733878;
for (f = 0; f < n.length; f += 16) d = c(d = c(d = c(d = c(d = e(d = e(d = e(d = e(d = u(d = u(d = u(d = u(d = o(d = o(d = o(d = o(a = d, v = o(h = v, C = o(g = C, l = o(i = l, d, v, C, n[f], 7, -680876936), d, v, n[f + 1], 12, -389564586), l, d, n[f + 2], 17, 606105819), C, l, n[f + 3], 22, -1044525330), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 4], 7, -176418897), d, v, n[f + 5], 12, 1200080426), l, d, n[f + 6], 17, -1473231341), C, l, n[f + 7], 22, -45705983), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 8], 7, 1770035416), d, v, n[f + 9], 12, -1958414417), l, d, n[f + 10], 17, -42063), C, l, n[f + 11], 22, -1990404162), v = o(v, C = o(C, l = o(l, d, v, C, n[f + 12], 7, 1804603682), d, v, n[f + 13], 12, -40341101), l, d, n[f + 14], 17, -1502002290), C, l, n[f + 15], 22, 1236535329), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 1], 5, -165796510), d, v, n[f + 6], 9, -1069501632), l, d, n[f + 11], 14, 643717713), C, l, n[f], 20, -373897302), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 5], 5, -701558691), d, v, n[f + 10], 9, 38016083), l, d, n[f + 15], 14, -660478335), C, l, n[f + 4], 20, -405537848), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 9], 5, 568446438), d, v, n[f + 14], 9, -1019803690), l, d, n[f + 3], 14, -187363961), C, l, n[f + 8], 20, 1163531501), v = u(v, C = u(C, l = u(l, d, v, C, n[f + 13], 5, -1444681467), d, v, n[f + 2], 9, -51403784), l, d, n[f + 7], 14, 1735328473), C, l, n[f + 12], 20, -1926607734), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 5], 4, -378558), d, v, n[f + 8], 11, -2022574463), l, d, n[f + 11], 16, 1839030562), C, l, n[f + 14], 23, -35309556), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 1], 4, -1530992060), d, v, n[f + 4], 11, 1272893353), l, d, n[f + 7], 16, -155497632), C, l, n[f + 10], 23, -1094730640), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 13], 4, 681279174), d, v, n[f], 11, -358537222), l, d, n[f + 3], 16, -722521979), C, l, n[f + 6], 23, 76029189), v = e(v, C = e(C, l = e(l, d, v, C, n[f + 9], 4, -640364487), d, v, n[f + 12], 11, -421815835), l, d, n[f + 15], 16, 530742520), C, l, n[f + 2], 23, -995338651), v = c(v, C = c(C, l = c(l, d, v, C, n[f], 6, -198630844), d, v, n[f + 7], 10, 1126891415), l, d, n[f + 14], 15, -1416354905), C, l, n[f + 5], 21, -57434055), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 12], 6, 1700485571), d, v, n[f + 3], 10, -1894986606), l, d, n[f + 10], 15, -1051523), C, l, n[f + 1], 21, -2054922799), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 8], 6, 1873313359), d, v, n[f + 15], 10, -30611744), l, d, n[f + 6], 15, -1560198380), C, l, n[f + 13], 21, 1309151649), v = c(v, C = c(C, l = c(l, d, v, C, n[f + 4], 6, -145523070), d, v, n[f + 11], 10, -1120210379), l, d, n[f + 2], 15, 718787259), C, l, n[f + 9], 21, -343485551), l = r(l, i), d = r(d, a), v = r(v, h), C = r(C, g);
return [l, d, v, C]
}
function i(n) {
var r, t = "", o = 32 * n.length;
for (r = 0; r < o; r += 8) t += String.fromCharCode(n[r >> 5] >>> r % 32 & 255);
return t
}
function a(n) {
var r, t = [];
for (t[(n.length >> 2) – 1] = void 0, r = 0; r < t.length; r += 1) t[r] = 0;
var o = 8 * n.length;
for (r = 0; r < o; r += 8) t[r >> 5] |= (255 & n.charCodeAt(r / 8)) << r % 32;
return t
}
function h(n) {
var r, t, o = "0123456789abcdef", u = "";
for (t = 0; t < n.length; t += 1) r = n.charCodeAt(t), u += o.charAt(r >>> 4 & 15) + o.charAt(15 & r);
return u
}
function g(n) {
return unescape(encodeURIComponent(n))
}
function l(n) {
return function (n) {
return i(f(a(n), 8 * n.length))
}(g(n))
}
function d(n, r) {
return function (n, r) {
var t, o, u = a(n), e = [], c = [];
for (e[15] = c[15] = void 0, 16 < u.length && (u = f(u, 8 * n.length)), t = 0; t < 16; t += 1) e[t] = 909522486 ^ u[t], c[t] = 1549556828 ^ u[t];
return o = f(e.concat(a(r)), 512 + 8 * r.length), i(f(c.concat(o), 640))
}(g(n), g(r))
}
window.md5 = function (n, r, t) {
return r ? t ? d(r, n) : function (n, r) {
return h(d(n, r))
}(r, n) : t ? l(n) : function (n) {
return h(l(n))
}(n)
}
}();
function get_sign(timestamp,pageNumber) {
return window.token = window.md5("tuling" + timestamp + pageNumber)
}
//我们就保留主要的参数生成函数,我还把函数名换成get_sign,后面python调用知道这个是干嘛用的
//
const timestamp = new Date().getTime()
//我们把上面那个函数的这句单独拿出来,我们选择写在函数外面,但要传参进去get_sign()这个函数里面
//不然window.md5("tuling" + timestamp + pageNumber)这个语句里面的timestamp识别不到
console.log(get_sign(timestamp,2)) //用于测试2是页码后面在python里面用for循环进行替换
下面这句直接删掉
***
const queryString = new URLSearchParams(params).toString();
fetch(`/api/problem-detail/${problemId}/data/?${queryString}`)
.then(response => response.json())
.then(data => updatePageContent(data))
.catch(error => console.error('Error fetching problem details:', error));
}
***
运行js代码发现可以生成它加密后的sign
说明:它每个sgin都不一样是因为时间戳改变而改变,所以每运行一次这个加密后的值都会变
第一次
第二次
![]()
第三次
![]()
python代码如下
import requests
import execjs #导入execjs这个东西是解析你导入js代码的库,如果没有安装就用不了需要在下方的命令行安装 pip install pyexecjs
import time #导入time库我们用这个去模仿它js那个语句生成的时间戳
with open('get_JS.js','r',encoding='utf-8') as f:
js_code = f.read()
numb = 0
timestamp = int(time.time()*1000) # 与 Python 的 int(time.time()*1000) 完全等效
# new Date().getTime() 是 JavaScript 中获取毫秒时间戳的标准方法
for page in range(1,21):
url = 'https://www.mashangpa.com/api/problem-detail/4/data/'
header = {
'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36',
'referer':'https://www.mashangpa.com/problem-detail/4/',
'cookie':'自己的cookie'
}
sign = execjs.compile(js_code).call('get_sign',timestamp,page)
# .compile() execjs库使用方法
#js_code在这段Python代码中具体指的是从 get_sign.js 文件读取的全部JavaScript代码内容
# .call是在execjs库中调用 JavaScript 函数的方法。它让 Python 能够执行 JavaScript 代码并获取返回值
#get_sign js文件里面定义的函数,你js文件定义的函数名是什么这里就是什么
#timestamp 时间戳
# page 上面for循环定义的页码
data = {'page':f'{page}','sign':sign,'_ts':timestamp} #定义一个字典把值填写到键的右边每个字段用逗号隔开
response = requests.get(url=url,headers=header,params=data) #params=data 把data这个字典传参进去
numberlist = response.json()['current_array']
for num in numberlist:
numb += num
print(numb)
方法二、
既然我们知道它是怎实现的这个加密后的字符,我们可以省略掉他的js代码
用python的hashlib库的md5加密来进行实现
import requests
import hashlib #导入hashli用这个进行md5加密
import time #导入time库我们用这个去模仿它js那个语句生成的时间戳
numb = 0
timestamp = int(time.time()*1000) # 与 Python 的 int(time.time()*1000) 完全等效
# new Date().getTime() 是 JavaScript 中获取毫秒时间戳的标准方法
for page in range(1,21):
url = 'https://www.mashangpa.com/api/problem-detail/4/data/'
header = {
'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36',
'referer':'https://www.mashangpa.com/problem-detail/4/',
'cookie':'自己的cookie'
}
sign = hashlib.md5("'tuling' + timestamp + page".encode(encoding='GBK')).hexdigest()
#hashlib.md5()md5加密
#tuling 字符
#timestamp 时间戳
#page 页码
#.encode(encoding='GBK')) 进行GBK编码
#.hexdigest() 返回字符串
data = {'page':f'{page}','sign':sign,'_ts':timestamp} #定义一个字典把值填写到键的右边每个字段用逗号隔开
response = requests.get(url=url,headers=header,params=data) #params=data 把data这个字典传参进去
numberlist = response.json()['current_array']
for num in numberlist:
numb += num
print(numb)



