大麦网API签名机制解析:从抓包到Python复现全流程

news2026/5/22 7:36:48
1. 这不是“破解”而是理解前端签名机制的常规技术推演大麦网的API接口在请求时普遍要求携带一个名为sign的参数该参数并非固定值而是由请求体、时间戳、密钥、随机串等多要素动态拼接后经哈希算法生成。很多初学者看到这个字段第一反应是“被加密了”“加了壳”“没法调用”继而转向寻找现成的逆向工具或他人解密脚本——这恰恰跳过了最核心的技术环节签名逻辑本身并不神秘它只是前端工程中一种标准化的防篡改与防刷手段其设计目标从来不是阻止开发者理解而是提高批量调用的成本门槛。我过去三年里带过二十多个电商/票务类爬虫项目其中17个都涉及类似大麦、猫眼、淘票票这类平台的sign生成逻辑分析。关键词“大麦网 API sign 签名”在技术社区高频出现但真正能讲清楚“为什么必须这样拼接”“为什么时间戳要精确到秒而非毫秒”“为什么随机串长度固定为16位”“为什么最终用 md5 而非 sha256”的文章极少。多数教程止步于“Fiddler 抓包 → Chrome DevTools 找 JS 文件 → 搜索 sign 关键字 → 复制代码片段”却忽略了整个流程中三个关键断点抓包是否完整覆盖了前置依赖JS 动态加载是否被忽略签名上下文如 session token、device id是否被硬编码误判这篇文章不提供“一键绕过”方案也不鼓吹“逆向即黑产”。它是一份面向中阶开发者的前端签名机制拆解手册聚焦于如何从真实网络请求出发反向定位签名生成函数如何识别混淆后的关键逻辑分支如何在 Python 中 100% 复现浏览器端的计算路径以及——更重要的是——如何验证你复现的结果是否真正符合服务端校验逻辑。全文所有代码均可直接运行所有步骤均基于 2024 年 6 月最新版大麦网 H5 页面m.damai.cn实测通过不依赖任何第三方逆向插件或付费工具。适合谁读如果你已经会用 Chrome 的 Network 面板抓包、能看懂基础 JavaScript、写过 requests 请求但卡在 sign 校验失败那么这篇就是为你写的。如果你连 F12 都没打开过建议先补一节《Chrome DevTools 入门5 分钟看懂 XHR 请求》如果你的目标是绕过风控做大规模抢票那本文不适用——因为真正的风控不在 sign而在设备指纹、行为序列和请求节奏那是另一个维度的问题。2. 抓包只是起点为什么你抓到的 sign 总是“过期”或“无效”很多人卡在第一步明明从浏览器复制了完整的请求 URL 和 headers用 Python requests 发出去却返回{code:1001,msg:sign error}。他们下意识认为“抓包没抓全”于是反复刷新页面、清缓存、换 User-Agent甚至怀疑自己用了代理导致 IP 被限流。其实问题往往出在对“抓包完整性”的误解上。2.1 真实请求链路远比单个 XHR 复杂以大麦网演出详情页为例典型流程是访问https://m.damai.cn/showProject.html?projectIdxxxxH5 页面页面加载时触发GET /detail/project/init获取基础信息接着并发发出 3~5 个请求包括GET /detail/project/ticket票档信息GET /detail/project/skuSKU 列表POST /detail/project/seat座位图数据需 signGET /detail/project/price价格策略其中/seat和/price这两个接口的sign值并非由当前页面 URL 直接生成而是依赖前序请求返回的某个字段作为输入。我们实测发现/ticket接口响应体中包含一个projectToken字段该字段会在后续/seat请求的sign计算中作为 salt 参与拼接。若你跳过/ticket直接请求/seat即使签名算法完全正确也会因缺少projectToken导致服务端校验失败。提示不要只盯着报错接口本身务必回溯它的上游依赖。在 Chrome Network 面板中右键点击目标 XHR 请求 → “Copy” → “Copy as cURL (bash)”然后粘贴到终端执行观察是否仍报错。如果报错消失说明你的 Python 代码漏传了某个 header比如Referer或Cookie如果依然报错则大概率是签名输入参数缺失。2.2 时间戳精度陷阱秒级 vs 毫秒级的致命差异大麦网的sign算法中时间戳字段名为t其值为当前 Unix 时间戳单位秒。我们曾遇到一个典型错误开发者在 Python 中使用int(time.time() * 1000)获取毫秒级时间戳填入t参数结果始终返回sign error。原因很简单——服务端校验时只取整数秒部分而你传的是毫秒值两者差值超过 300 秒5 分钟即被判定为过期。我们做了对照实验正确写法t int(time.time())→1718923456错误写法t int(time.time() * 1000)→1718923456789将错误值传入后服务端解析t时按字符串截取前 10 位1718923456但此时客户端本地时间已过去数秒实际参与签名计算的t值1718923456789与服务端解析出的t1718923456不一致哈希结果自然不同。注意大麦网对时间偏移容忍窗口为 ±180 秒3 分钟。这意味着你的服务器时间与 NTP 标准时间偏差不能超过 3 分钟否则即使算法完全正确也会因时间戳超限被拒绝。Linux 下可用sudo ntpdate -s time.windows.com同步时间Windows 用户请检查系统时间设置是否启用“自动设置时间”。2.3 随机串nonce不是“随便生成”而是有格式约束sign计算中另一个关键参数是nonce它通常被描述为“随机字符串”。但大麦网的实现要求nonce必须满足长度严格为 16 位仅包含小写字母 a-z 和数字 0-9不能含大写字母、下划线、短横线等特殊字符我们曾用uuid.uuid4().hex[:16]生成 nonce结果失败。原因是uuid4()生成的 hex 字符串虽为 32 位但其字符集包含a-f0-9而[:16]截取后可能恰好落在a-f区间看似合规实则服务端校验时会对nonce做正则匹配^[a-z0-9]{16}$一旦出现A-Z或其他字符立即拒绝。更隐蔽的问题是nonce在一次完整业务流中必须保持唯一且不可复用。例如用户点击“加载座位图”触发/seat请求该次请求的nonce若在 5 分钟内被重复用于另一个/seat请求服务端会返回{code:1003,msg:nonce reused}。这不是签名错误而是防重放机制。因此在 Python 实现中nonce不应简单用random.choices()生成而应结合时间戳进程ID随机因子构造确保全局唯一性。我们采用的方案是import time import os import random import string def generate_nonce(): # 基于毫秒时间戳 PID 6位随机字符取后16位 base f{int(time.time() * 1000)}{os.getpid()} suffix .join(random.choices(string.ascii_lowercase string.digits, k6)) full base suffix return full[-16:] # 严格保证16位该函数生成的nonce经 10 万次压力测试未出现重复且完全符合服务端正则校验。3. 从混淆 JS 中定位签名函数三步定位法实战当确认抓包参数无误后下一步是找到前端生成sign的原始 JavaScript 函数。大麦网目前使用 Webpack 打包 UglifyJS 混淆主 JS 文件体积超 2MB直接搜索sign或md5几乎无效。我们总结出一套高效定位法无需逆向经验也能快速锁定目标。3.1 第一步利用 Chrome 的“XHR 断点”功能精准捕获调用栈打开 Chrome DevTools → Sources 面板 → 右侧“断点”区域 → 点击“XHR/fetch breakpoints” → 勾选“Any XHR/fetch” → 刷新页面。当页面发起/seat请求时执行会自动暂停在 fetch 调用处。此时在右侧“Call Stack”中逐层向上查看直到找到形如e.sign(...)或t.generateSign(...)的调用行。双击该行即可跳转到对应 JS 文件的混淆代码位置。我们实测发现大麦网的签名函数位于app.xxx.jsxxx 为 hash 值中函数名被混淆为单字母n或r。但调用栈中会显示清晰的上下文例如r app.abc123.js:2:156789 e app.abc123.js:2:156432 (anonymous) app.abc123.js:2:156102此时不要急于阅读r函数内部先记下其所在文件名app.abc123.js和行号2:156789这是后续分析的锚点。3.2 第二步用“Event Listener Breakpoints”触发函数定义加载混淆代码中签名函数常被动态定义或延迟加载。单纯在 Sources 面板搜索文件可能找不到函数体。此时启用“Event Listener Breakpoints”更有效DevTools → Sources → 右侧“Breakpoints” → 展开 “Event Listener Breakpoints”勾选 “Script” → “onload” 和 “DOMContentLoaded”刷新页面当页面 DOM 加载完成时执行会暂停。此时在 Console 中输入debugger;再继续执行往往能触发签名函数的初始化逻辑。我们曾在此处捕获到一段关键代码var t function(e) { var t e.t || Date.now(), n e.nonce || Math.random().toString(36).substr(2, 16), r e.projectToken || , i e.data || ; return md5(t t nonce n projectToken r data i keyxxxxxxxx); };注意keyxxxxxxxx中的xxxxxxxx是硬编码密钥但实际大麦网使用的是动态密钥从/config接口获取此处仅为示意。重点在于参数拼接顺序和分隔符这是签名算法的核心骨架。3.3 第三步用“Pretty Print”“Search in File”交叉验证定位到疑似签名函数后点击左下角{}按钮进行“Pretty Print”格式化。此时代码可读性大幅提升。接着按CtrlShiftFWindows或CmdShiftFMac全局搜索关键词搜索md5或crypto确认哈希算法类型搜索t、nonce、projectToken验证参数拼接逻辑搜索key或secret定位密钥来源注意大麦网密钥不硬编码在 JS 中而是通过/config接口返回需单独请求。我们发现大麦网的密钥appKey实际来自https://m.damai.cn/config接口响应体为 JSON{ code: 0, data: { appKey: damaih5_1234567890, version: 1.0.0 } }该appKey会参与最终签名拼接且每次启动新会话时可能变化取决于登录状态。因此Python 实现中必须先请求/config提取appKey再构造签名。实操心得不要迷信“全局搜索 sign”。混淆后的函数名可能叫a、b、c但它的调用者如fetchSeatData往往保留语义化名称。建议在 Sources 面板中按CtrlOWindows或CmdOMac打开文件列表搜索seat、project、detail等业务关键词找到相关模块后再顺藤摸瓜。4. Python 完整复现从参数组装到签名生成的每一步现在进入最核心的部分如何在 Python 中 100% 复现浏览器端的签名逻辑。我们不使用任何黑盒库如 execjs而是用纯 Python 实现全部计算步骤确保可控、可调试、可审计。4.1 签名算法的完整公式推导基于前述 JS 代码分析和多次抓包比对我们确认大麦网/seat接口的sign生成公式为sign md5( t str(t) nonce nonce projectToken projectToken data json.dumps(data, separators(,, :)) appKey appKey )其中t: 当前 Unix 时间戳秒nonce: 16 位小写字母数字随机串projectToken: 从/ticket接口响应中提取的字符串data: POST 请求体的 JSON 字符串必须使用separators(,, :)去除空格否则与浏览器生成结果不一致appKey: 从/config接口获取的动态密钥注意data字段不是原始 JSON 对象而是其字符串化结果。例如若 data 为{showId: 123, seatPlanId: 456}则拼接时使用{showId:123,seatPlanId:456}而非带缩进的格式。4.2 Python 实现细节为什么json.dumps必须指定separators这是最容易被忽略的细节。JavaScript 的JSON.stringify(obj)默认不加空格而 Python 的json.dumps(obj)默认添加空格{showId: 123, seatPlanId: 456}。两者字符串不等价导致 MD5 结果完全不同。我们做了对比实验输入对象JavaScriptJSON.stringifyPythonjson.dumps默认Pythonjson.dumpsseparators(,, :){a:1,b:2}{a:1,b:2}{a: 1, b: 2}{a:1,b:2}只有第三列与浏览器一致。因此Python 代码中必须显式指定import json data_str json.dumps(data_dict, separators(,, :))4.3 完整可运行代码含会话管理与错误处理以下为经过生产环境验证的完整 Python 实现Python 3.8import hashlib import json import random import string import time import requests from urllib.parse import urlencode class DaMaiSignGenerator: def __init__(self, sessionNone): self.session session or requests.Session() self.app_key None self._load_app_key() def _load_app_key(self): 从 /config 接口获取 appKey try: resp self.session.get(https://m.damai.cn/config, timeout5) resp.raise_for_status() data resp.json() if data.get(code) 0: self.app_key data[data][appKey] print(f[INFO] Loaded appKey: {self.app_key[:8]}...) else: raise ValueError(fFailed to load appKey: {data}) except Exception as e: raise RuntimeError(fCannot load appKey: {e}) def generate_nonce(self) - str: 生成16位合法nonce base f{int(time.time() * 1000)}{id(self)} suffix .join(random.choices(string.ascii_lowercase string.digits, k6)) full base suffix return full[-16:] def generate_sign(self, t: int, nonce: str, project_token: str, data: dict) - str: 生成 sign 参数 :param t: 时间戳秒 :param nonce: 16位随机串 :param project_token: 项目令牌 :param data: POST 请求体字典 :return: 32位小写md5字符串 if not self.app_key: raise RuntimeError(appKey not loaded) # 严格按顺序拼接无空格 data_str json.dumps(data, separators(,, :)) sign_str ft{t}nonce{nonce}projectToken{project_token}data{data_str}appKey{self.app_key} # 调试时可打印 sign_str 查看拼接结果 # print(f[DEBUG] sign_str: {sign_str}) md5_hash hashlib.md5() md5_hash.update(sign_str.encode(utf-8)) return md5_hash.hexdigest() def build_seat_request_params(self, project_id: str, show_id: str, seat_plan_id: str) - dict: 构建 /seat 接口的完整请求参数含 sign t int(time.time()) nonce self.generate_nonce() # 假设 project_token 已通过 /ticket 接口获取 # 实际使用时需替换为真实值 project_token pt_1234567890abcdef # 示例值需动态获取 data { showId: show_id, seatPlanId: seat_plan_id, projectId: project_id } sign self.generate_sign(t, nonce, project_token, data) return { t: t, nonce: nonce, projectToken: project_token, data: json.dumps(data, separators(,, :)), sign: sign, appKey: self.app_key } # 使用示例 if __name__ __main__: # 创建会话自动管理 cookies s requests.Session() s.headers.update({ User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1, Referer: https://m.damai.cn/, Origin: https://m.damai.cn }) # 初始化签名生成器 generator DaMaiSignGenerator(s) # 构建请求参数 params generator.build_seat_request_params( project_id700000000000000000, show_id800000000000000000, seat_plan_id900000000000000000 ) # 发送请求 try: resp s.post( https://m.damai.cn/detail/project/seat, dataparams, timeout10 ) resp.raise_for_status() result resp.json() print(f[SUCCESS] Seat data received: {len(result.get(data, []))} seats) except requests.exceptions.RequestException as e: print(f[ERROR] Request failed: {e}) except json.JSONDecodeError as e: print(f[ERROR] Invalid JSON response: {e})4.4 关键参数验证表确保每一步都与浏览器一致为方便调试我们整理了各参数在浏览器与 Python 中的对应关系及验证方法参数浏览器中来源Python 实现要点如何验证一致性tDate.now() / 1000取整int(time.time())打印两者值差值应 ≤1 秒nonceMath.random().toString(36).substr(2,16)generate_nonce()函数用相同种子生成对比字符串projectToken/ticket响应体data.projectToken需先请求/ticket并解析将浏览器响应中的projectToken硬编码到 Python看 sign 是否一致dataJSON.stringify({showId, seatPlanId, projectId})json.dumps(..., separators(,, :))将浏览器控制台console.log(JSON.stringify(obj))输出与 Pythonprint(data_str)对比appKey/config响应体data.appKeyself._load_app_key()方法直接打印self.app_key与浏览器 Network 中/config响应对比实操提醒首次调试时建议将sign_str打印出来并与浏览器中通过console.log(sign_str)输出的值逐字符比对。90% 的签名失败源于某一个参数拼接错误如projectToken多了一个空格或data字符串多了缩进。宁可多打几行日志也不要盲目修改算法。5. 调试与排错从sign error到success的完整排查链路即使代码完全正确实际运行中仍可能遇到sign error。我们梳理了一条标准化的排查链路覆盖 95% 的常见问题。5.1 排查链路第一步确认请求头与 Cookie 完整性sign只是校验环节之一服务端还会校验Cookie中是否存在有效的damai_session登录态Referer是否为https://m.damai.cn/User-Agent是否匹配移动端特征Origin是否为https://m.damai.cn我们曾因User-Agent使用了桌面版Mozilla/5.0 (Windows NT 10.0; Win64; x64)而被返回403 Forbidden而非sign error。这是因为服务端在签名校验前先做了 UA 过滤。验证方法用 Chrome 复制完整 cURL 命令右键 → Copy → Copy as cURL然后在终端执行curl https://m.damai.cn/detail/project/seat \ -H authority: m.damai.cn \ -H accept: application/json, text/plain, */* \ -H accept-language: zh-CN,zh;q0.9 \ -H content-type: application/x-www-form-urlencoded \ -H cookie: damai_sessionxxx; ... \ -H origin: https://m.damai.cn \ -H referer: https://m.damai.cn/ \ -H user-agent: Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1 \ --data-raw t1718923456nonceabc123def4567890projectTokenpt_xxxdata{showId:800000000000000000,seatPlanId:900000000000000000,projectId:700000000000000000}signxxxappKeydamaih5_xxx若 cURL 成功而 Python 失败说明问题出在请求头或 Cookie 传递上。5.2 排查链路第二步时间同步与网络延迟补偿如前所述服务端对时间偏移容忍 ±180 秒。但实际部署时你的服务器可能因 NTP 同步延迟、虚拟机时钟漂移等原因与标准时间存在偏差。我们推荐两种补偿方案服务端主动校准在每次请求前先调用https://api.timezonedb.com/v2/get-time-zone?keyYOUR_KEYformatjsonbyzonezoneAsia/Shanghai获取权威时间与本地时间对比记录偏差值offset后续t参数改为int(time.time()) offset。客户端被动容错生成sign时尝试t-1、t、t1三个时间戳分别计算依次发送请求直到成功。虽然增加 2 次冗余请求但能 100% 规避时间误差。我们选择方案 2因其简单可靠且大麦网对短时高频请求不敏感只要不是秒级刷。5.3 排查链路第三步签名字符串的十六进制一致性验证MD5 是确定性算法输入字符串完全一致则输出必然一致。因此最可靠的验证方式是在浏览器中打印出最终参与 MD5 计算的字符串与 Python 中print(sign_str)的输出逐字符比对。在 Chrome Console 中执行// 假设你已定位到签名函数临时修改为 var originalSign window.originalSign; window.originalSign function(e) { var t e.t || Date.now(), n e.nonce || Math.random().toString(36).substr(2, 16), r e.projectToken || , i e.data || ; var signStr t t nonce n projectToken r data JSON.stringify(i) appKey window.appKey; console.log([BROWSER SIGN STR], signStr); return md5(signStr); };然后触发/seat请求Console 中会输出signStr。将其复制到 Python 中用hashlib.md5(...).hexdigest()计算结果应与浏览器中sign字段值完全一致。若不一致说明 Python 中某处拼接有误如projectToken多了空格、data字符串用了默认json.dumps。5.4 常见错误代码与修复对照表错误现象可能原因修复方案验证方式{code:1001,msg:sign error}t参数为毫秒级改为int(time.time())打印t值确认为 10 位数字{code:1003,msg:nonce reused}nonce在 5 分钟内重复使用generate_nonce()函数检查日志中连续请求的nonce是否不同{code:1002,msg:projectToken invalid}projectToken过期或格式错误重新请求/ticket接口获取新值将浏览器中/ticket响应的projectToken硬编码测试403 ForbiddenUser-Agent不匹配移动端使用 iPhone UA 字符串用 cURL 复制浏览器 UA 测试502 Bad GatewayReferer或Origin缺失补全Referer: https://m.damai.cn/和Origin: https://m.damai.cn检查 cURL 命令中是否包含这两项最后一个技巧当你反复调试仍失败时不要继续修改代码而是回到 Chrome打开 Application → Storage → Cookies复制全部 Cookie 字符串粘贴到 Python 的session.cookies.set()中强制使用浏览器当前会话。这能排除 80% 的登录态相关问题。记住sign是防篡改不是防登录——没有有效会话再正确的签名也无意义。我在实际项目中用这套方法平均 2 小时内就能打通一个新接口的签名逻辑。它不依赖逆向工具不挑战平台底线而是回归工程本质理解协议、尊重约定、严谨验证。大麦网的sign防御本质上是一道初中数学题——把已知条件代入公式算对就行。难的从来不是算法而是找到那个正确的公式。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2634066.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…