资讯详情

Temu验证码逆向实战:从接口抓包到轨迹生成的完整技术解析

📅 2026/9/24 18:35:51 | 华诺云谱 👁 阅读
Temu验证码逆向实战:从接口抓包到轨迹生成的完整技术解析
1. 项目回顾为什么要碰Temu的验证码先说结论Temu验证码逆向这个事说白了就是跨境卖家、数据采集工程师和做竞品分析的团队在自动化流程里绕不开的一道坎。Temu现在风头正劲平台上的商品数据、价格策略、销量排行都是无数卖家眼里的香饽饽。但你想用脚本批量拉数据平台也不是吃素的——滑块验证码、图形点选、行为轨迹检测一层套一层。我自己最早碰这个项目就是帮一个做选品分析的团队解决商品数据抓取时的验证码拦截问题当时手动过验证码一天能点废三个鼠标效率低得让人抓狂。这篇文章我不打算写那种“某某平台一键破解”的标题党内容而是把自己从头到尾梳理Temu验证码体系的思路、实操步骤、踩过的坑以及最后稳定运行的方案完整拆给你看。适合三类人正在做跨境电商数据采集的技术同学做竞品价格监控的运营团队对JS逆向和验证码识别技术感兴趣的前端/爬虫工程师不管你是刚入行的新手还是已经写过不少采集脚本的老手这篇文章里都有值得你参考的东西。下面我尽量按照“从认识到实操再到排坑”的顺序来讲保证你能一步步跟着走下来。2. 验证码逆向的整体思路与方案选型2.1 Temu验证码体系的真实构成先说一个很多人容易误解的点Temu的验证码不是只有一种它是一个组合拳体系。我在实际逆向过程中至少遇到三类一类是图形滑块验证码最常见的场景是登录和商品接口高频访问时弹出。滑块样式和主流电商平台的类似但细节上做了不少改动后面我会详细讲。另一类是行为验证码比如要求你按顺序点击图中指定的文字或图案。这类验证码的难点不在识别图片本身而在模拟行为轨迹——鼠标从哪个位置移动、停顿多久、点击的落点偏移平台都有记录。还有一类是静默验证码这种最坑。你肉眼根本看不到任何验证界面但它通过采集浏览器指纹、Canvas画布特征、WebGL渲染信息等数据在后台完成人机判定。很多新手发现自己的脚本有时候能跑有时候被拦截其实大概率就是触发了静默验证。搞清楚这个体系很重要因为很多教程一上来就让你搞OCR识别结果只解决了其中一小部分问题。正确的思路是先搞清楚当前场景触发了哪种验证码再针对性设计识别和绕过方案。2.2 为什么不能只靠模拟点击硬过我第一次尝试的方案很粗暴用Selenium驱动浏览器配合坐标定位直接拖滑块。结果发现两个问题第一滑块拖动的轨迹特征太明显。真实用户拖动滑块时加速度是有起伏的甚至会有轻微的回退。而代码直接从一个坐标线性移动到另一个坐标或者即使用了加速减速曲线也很容易被检测到——因为平台会记录你整条轨迹的每一帧坐标点然后和真人数据做聚类对比。第二验证码的出现频次会动态变化。同一个IP和同一套浏览器指纹下连续通过几次验证码后平台会调高风险等级下一次可能就换成更复杂的图形点选或者直接进入静默验证。这说明平台的风控是动态的你只靠一套固定方案很难长期稳定。后来我换了思路验证码逆向的核心不是“绕”而是理解它的生成和校验逻辑。只要你能把验证码的生成参数、校验参数、加密过程摸清楚就能在脚本里直接模拟请求跳过用户交互这一步。这才是效率最高的方案。2.3 逆向方案的三大路线对比做Temu验证码逆向行业内主流路线有三条我简单对比下方案路线实现难度稳定性适用场景纯图像识别模拟操作低低易被轨迹检测低频个人使用JS逆向直接构造请求高高不依赖UI中高频商业采集浏览器自动化行为模拟中中需持续调参中小规模爬取纯图像识别模拟操作适合刚入门用来练手但说实话生产环境用它风险太高。浏览器自动化加行为模拟比较折中但如果平台风控升级你也得跟着升级轨迹算法。JS逆向构造请求是性能最高、最稳定的方案但对逆向功底要求高而且需要定期维护。我自己的工程实践是混合路线用JS逆向拿到验证码和校验相关的接口参数再配合浏览器自动化去执行复杂验证两者互补。这样既避免了全程依赖UI操作的低效率又能在遇到更复杂验证时兜底。3. 核心细节解析从抓包到加密参数定位3.1 环境准备与抓包工具配置开始逆向之前先把环境准备好。我用的工具组合如下Chrome浏览器版本尽量保持最新DevTools协议支持更完善Charles或Fiddler抓包工具用于定位接口请求Node.js环境用于运行和调试逆向出来的JS代码Python 3.8用于后续写调度脚本和识别算法抓包配置上有个细节需要注意Temu的很多接口走的是HTTPS而且做了证书校验你直接装Charles的SSL代理证书有时候会被检测到。我的做法是用Chrome的--ignore-certificate-errors参数启动配合Charles的SSL代理这样能避免大部分证书校验问题。但这里要提醒一句这个方法只适合本地开发和调试生产环境还是应该用更合规的技术方案。启动命令大概是这样的/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --ignore-certificate-errors --proxy-server127.0.0.1:8888Windows用户把路径换成你的Chrome安装路径就行。启动之后你会发现Charles里开始刷出大量的请求记录。接下来就是要在这个信息流里找到验证码相关的那几个关键接口。3.2 关键接口定位与参数分析我在实际操作中验证码相关的接口主要集中在两个域名下一个是生成验证码的接口另一个是校验验证码的接口。通过Charles过滤关键词比如captcha、verify、slider等能快速缩小范围。以图形滑块验证码为例生成接口返回的JSON数据大概长这样{ captcha_id: a3f8b9c2d1e04f5a8b7c6d5e4f3a2b1, bg_image: https://xxx.cdn.com/captcha/bg_12345.jpg, slider_image: https://xxx.cdn.com/captcha/slider_12345.png, y_position: 156, challenge: abc123def456ghi789 }这里的captcha_id是本次验证的唯一会话标识后续所有校验请求都要带上它。bg_image是背景图slider_image是滑块图y_position是滑块应该在的位置的纵坐标challenge是服务端下发的挑战码。校验接口一般长这样{ captcha_id: a3f8b9c2d1e04f5a8b7c6d5e4f3a2b1, answer: {\x\: 286, \y\: 156, \trace\: [[0,0,0],[12,3,18],...]}, challenge: abc123def456ghi789, sign: 8f4d1a2b3c4d5e6f7a8b9c0d1e2f3a4b }关键就在于answer字段里的坐标和轨迹数据以及sign字段的加密结果。坐标决定了滑块的目标位置轨迹决定了你是否像真人而sign则是对这些数据的完整性校验。这三个点就是整个逆向工程的核心目标。3.3 加密参数break point定位与调用栈分析拿到接口参数后下一步就是找到生成这些参数的JS代码。我的做法是在Chrome的Sources面板里搜索关键字sign定位到加密函数的位置然后下断点。这里有个很实用的技巧先不要全量格式化混淆的JS文件而是直接搜索关键字找到关键代码块再格式化。因为Temu的前端JS做了重度混淆整个文件格式化后有几千行全量找代码很浪费时间。比如搜索sign关键字我定位到一段类似这样的代码function generateSign(params) { var sortedParams sortKeys(params); var queryString Object.keys(sortedParams) .map(function(key) { return key encodeURIComponent(sortedParams[key]); }) .join(); var signStr queryString secret_keysfl3k2j1h0g9f8d7s6a5; return md5(signStr); }secret_key是硬编码在前端代码里的但不同接口可能用不同的key而且平台会不定期更换。所以你不能把找到的key写死需要在代码里做一个动态提取机制每次从最新的JS文件里自动提取。这个我在后面章节细讲。3.4 滑块轨迹生成的核心算法滑块轨迹是整个验证码校验中最有讲究的部分。平台会对轨迹数据做频域分析和行为建模只做简单的线性移动必定被识别。我调试过大量轨迹后总结出的可行做法是用三段式轨迹模型——先加速、再匀速、最后减速微调。具体实现可以用Python模拟也可以把算法用JS实现后注入到浏览器里执行。我用Python举个例子这样方便你理解轨迹生成逻辑import random import time def generate_trace(distance): 生成模拟真人滑块轨迹 trace [] current_x 0 current_y random.randint(-3, 3) t 0 # 第一阶段加速启动 while current_x distance * 0.6: current_x random.randint(3, 7) current_y random.uniform(-1, 1) t random.randint(8, 15) trace.append([current_x, current_y, t]) # 第二阶段匀速接近 while current_x distance * 0.95: current_x random.randint(2, 4) current_y random.uniform(-0.8, 0.8) t random.randint(10, 20) trace.append([current_x, current_y, t]) # 第三阶段减速微调 while current_x distance: current_x random.randint(1, 2) current_y random.uniform(-0.5, 0.5) t random.randint(15, 30) trace.append([current_x, current_y, t]) return trace这个算法本身不复杂但有几个关键参数需要根据实际情况调整起始y偏移真人按住滑块时鼠标y坐标不会完全对齐会有几个像素的偏移加速的随机范围加速度太固定也容易被识别需要加随机扰动时间戳间隔每次移动记录的时间间隔不是均匀的真实场景中会有快慢变化overshoot行为很多真人拖动滑块时会拖过头一点然后往回微调这个行为可以通过最后一段“回退”来模拟我验过的组合里加上一次“overshoot”先超过目标2-3像素再回正的轨迹通过率明显更高。但没有一个轨迹生成算法能永远有效平台只要更新了行为检测模型你可能就得重新调参。4. 实操过程与核心环节实现4.1 图形验证码的OCR识别方案说完了滑块再聊聊图形点选验证码。这类验证码要求你在背景图中依次点击某些物体比如“请依次点击图中的凤凰、龙、麒麟”。逆向这种验证码核心就是两部分目标检测和点击顺序。目标检测的实现也有两条路接入第三方OCR服务比如云厂商的文字识别接口、打码平台等优点是准确率高缺点是付费且响应慢自建目标检测模型用现成的开源模型如YOLO系列微调优点是免费且可控缺点是你需要准备标注数据训练我的实践是先用打码平台验证流程是否跑通之后量大了再考虑自建模型。打码平台的核心用法是把验证码背景图传过去平台返回识别结果和目标坐标。但这里有个风险验证码返回的背景图通常带有干扰线、噪点有时候还有形变直接传原图识别率不高。所以我在传图前会先做一轮预处理去噪、增强对比度、裁掉多余边框。用OpenCV几行代码就能搞定import cv2 def preprocess_captcha(image_path): img cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) # 去噪 img cv2.GaussianBlur(img, (3, 3), 0) # 二值化 _, img cv2.threshold(img, 180, 255, cv2.THRESH_BINARY) return img预处理之后验证码里的主要元素会更清晰识别准确率能提升不少。但这里要注意过度处理也可能把关键特征抹掉所以各项参数要针对不同验证码风格做微调不是一套参数走天下。4.2 前端JS环境补全与加密函数调用定位到加密函数后接下来要做的就是把前端JS搬到Node.js里运行。但Temu这类网站的前端代码依赖浏览器环境直接丢到Node里通常跑不起来因为缺少window、document等对象。这个时候就需要环境补全。环境补全最简单的方案是引入jsdom库模拟出基本的浏览器对象npm install jsdom示例代码如下const { JSDOM } require(jsdom); const dom new JSDOM(!DOCTYPE htmlhtmlbody/body/html, { url: https://www.temu.com/, userAgent: Mozilla/5.0 ... }); global.window dom.window; global.document dom.window.document; global.navigator dom.window.navigator;然后把之前定位到的混淆JS文件加载进来就可以在Node环境里调用它的加密函数了const fs require(fs); const code fs.readFileSync(./captcha.js, utf-8); eval(code); // 在补全后的环境中执行 // 调用加密函数 const sign generateSign({ captcha_id: xxx, answer: xxx }); console.log(sign);这里要特别提醒尽量不要用eval执行远程代码会有严重的安全风险。更加稳妥的做法是把需要的JS代码抠出来做成独立的Node模块只暴露必要的方法。这个过程叫“JS代码剥离”是逆向工程中比较耗时间的部分。因为混淆后的代码里有很多自执行函数、变量重定义抠代码时很容易破坏它的内部状态依赖需要反复调试。4.3 验证码坐标偏移量的计算技巧无论是滑块还是点选最终提交给服务端的坐标都必须准确。很多人忽略了图片显示比例的问题前端页面展示的验证码图是经过CSS缩放或者被容器裁剪过的而你从接口拿到的原始图片尺寸可能完全不同。如果你直接把识别出来的坐标提交上去校验大概率失败。我处理这个问题的方法是写一个简单的比例换算函数def convert_coordinate(recognized_x, recognized_y, original_width, original_height, display_width, display_height): scale_x display_width / original_width scale_y display_height / original_height return round(recognized_x * scale_x), round(recognized_y * scale_y)还有一个细节是滑块验证码的目标位置。滑块要移动的距离不是“缺口所在坐标”本身而是缺口位置减去滑块初始位置的差值。这个差值才是你answer字段里需要填的值。我第一次做的时候直接把缺口的绝对坐标提交上去结果服务端一直提示验证失败后来才发现位移量算错了。另外有些平台的背景图上缺口会有一个动态偏移范围同一个背景图在不同会话下缺口位置可能是固定的也可能是上下浮动几个像素的。这个需要通过多次请求对比来确定一旦发现是浮动偏移你需要在生成坐标时也加入对应的随机偏移才能保证通过率稳定。4.4 完整流程串联一个最小可用脚本跑通上面的所有环节后我把整个流程串了起来。给你看一个简化版的Python脚本这里面包含了从请求验证码到提交校验的完整链路import requests import json session requests.Session() headers { User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64) x64..., Referer: https://www.temu.com/ } # 1. 请求验证码 captcha_resp session.get( https://xxx.temu.com/api/captcha/generate, headersheaders ) captcha_data captcha_resp.json() captcha_id captcha_data[captcha_id] bg_image_url captcha_data[bg_image] slider_image_url captcha_data[slider_image] # 2. 下载图片并识别缺口位置 bg_image download_image(bg_image_url) slider_image download_image(slider_image_url) target_x recognize_gap_position(bg_image, slider_image) # 3. 生成轨迹和签名 trace_data generate_trace(target_x) sign call_node_sign_function(captcha_id, target_x, trace_data) # 4. 提交校验 verify_payload { captcha_id: captcha_id, answer: json.dumps({ x: target_x, trace: trace_data }), sign: sign } verify_resp session.post( https://xxx.temu.com/api/captcha/verify, jsonverify_payload, headersheaders ) print(verify_resp.json())这个脚本是简化版真实环境中还需要处理代理IP轮换、Cookie同步、频率控制等问题。但它已经能帮你走通一遍完整的验证码逆向流程让你对整条链路有一个直观的认知。5. 常见问题与排查技巧实录5.1 验证码识别正确但校验依然失败这是我最常遇到的问题之一。如果你已经根据接口返回的图片成功识别出了目标位置但提交校验仍然失败排查思路可以从以下几个方向入手第一检查位移量的计算是否正确。我前面说过把缺口绝对坐标当成移动距离直接提交是新手最容易犯的错误。你先确认一下提交的x值是不是滑块从起点到目标点的实际位移。第二检查时间戳和轨迹数据是否合理。有些平台不仅校验目标位置还会校验整个拖动过程的总时长、轨迹形状和数据量。如果生成轨迹的时间间隔过于均匀或者总时长不合理比如0.5秒拖完一个长距离也会被判为机器操作。第三检查sign签名是否正确生成。签名参数往往包含了captcha_id、answer等内容的哈希值一旦你的请求体格式和签名算法使用的字符串拼接方式不一致服务端计算出来的签名就会不同。第四也是很多人忽略的检查cookie和其他请求头是否完整。验证码校验接口通常会要求当前会话的cookie有效如果你在请求过程中清理了cookie或者没有带上关键的会话标识字段校验必然失败。5.2 IP与设备指纹被风控标记怎么办跑Temu验证码逆向跑多了你会发现一个现象同一个IP下即使你的验证码每次都能正确通过但触发的频次会越来越频繁甚至最后访问任何页面都会弹出验证码。这个大概率就是被风控系统标记了。我试过有效的方法有这些动态代理IP池每次请求或短时间轮换一次IP避免单一IP高频访问。但要注意代理IP质量参差不齐有的数据中心IP反而更容易触发验证浏览器指纹伪装如果用的是浏览器自动化方案需要修改Canvas指纹、WebGL信息、时区、语言等特征保持指纹一致性而不是每次都变控制请求节奏给脚本加上随机延时模拟真实用户的浏览节奏避免短时间内的连续高频请求这三种方法组合使用能显著降低触发验证码的概率但也不是永久有效的。平台风控团队会持续更新策略发现你的行为模式后又可能重新拦截到那时候又要重新调整适配。5.3 JS文件更新导致签名算法失效签名算法失效是最让人头疼的维护问题。Temu的JS文件更新频率不算特别快但一旦更新了混淆逻辑原来的签名生成方式可能就失效了。表现为脚本突然开始大量校验失败或者在浏览器里手动操作正常但用脚本模拟就是不行。遇到这种情况我的处理步骤是重新抓包拿到最新的JS文件对比新旧JS文件的差异定位变化的函数用diff工具或BEACON类的AST分析工具找到加密函数的入口和输出抠出新的加密逻辑替换旧代码用多组历史请求数据做回归测试确认签名生成结果一致这个过程听起来简单实际做起来可能要花几个小时。尤其是平台改版后把固定的secret_key改成了动态获取方式你可能还要额外模拟一次获取key的请求。所以这里再强调一遍写逆向代码时不要把加密算法相关的参数写死尽量做成可配置的或者每次启动时动态获取。这样下次平台更新算法时你改配置就能适配不用重写整套代码。5.4 常见问题速查表整理一个速查表方便你遇到问题时快速定位问题现象可能原因解决方案滑块校验总是失败位移量计算错误确认提交的是位移量而非绝对坐标偶尔成功偶尔失败轨迹时间间隔过于规律加入随机扰动模拟减速与微调行为全部请求都开始弹验证码IP被标记或访问频率过高轮换代理IP加入随机延时脚本更新后突然全失败前端JS算法更新重新抓取JS文件更新签名算法校验接口返回参数错误缺少必要cookie或header补齐会话标识和浏览器指纹请求头图片识别定位不准未做预处理或图片缩放比例有误添加OpenCV预处理校准显示比例这张表基本覆盖了我在实际使用过程中遇到的主要问题。但需要记住的是这类平台的验证码机制是动态演进的今天的排查方案明天不一定适用关键还是掌握排查思路而不是死记某个具体的参数。6. 经验杂谈与避坑心得6.1 工具链选型建议做Temu验证码逆向工具选型直接决定投入产出比。我踩过不少工具链的坑最想提醒的是不要一上来就迷信重型框架。如果你只是跑通一个小流程直接用requests加Node.js就够了不需要上Scrapy这样的重型框架。爬虫框架确实提供了调度、去重、中间件等一堆功能但也会引入额外的复杂性和性能开销。对于验证码逆向场景核心复杂度已经很高再用框架反而束手束脚。Python加Node.js的组合是目前我验证过最顺手的Python负责整体流程调度、图像处理Node.js负责执行前端JS加密逻辑两者之间通过子进程或HTTP接口通信即可。如果你要求极致性能也可以用Python的PyExecJS库直接调用JS但要留意PyExecJS的维护状态和兼容性。6.2 日常维护的几个习惯验证码逆向不是“做完就完事”的项目它是一个需要持续维护的技术方案。以下这几个习惯是我在长期实践中沉淀下来的保持JS文件版本管理。每次抓到新版JS文件就把它存到单独的目录里并且记录变更时间。这样一旦平台更新导致脚本失效你可以快速回滚调试也能通过历史版本对比快速定位变化点。写日志尤其是失败日志。我的脚本里会把每次请求的验证码ID、识别结果、校验返回、响应时长等关键字段都记录到日志中。这样遇到问题时可以通过回溯日志快速定位是哪一环出了岔子。定期做回归测试。不要等到线上挂了才检查建议每周跑一遍全流程的回归测试。设定好一个监控提醒一旦测试失败自动通知开发者处理。这个习惯帮我避免了好几次大规模的故障。6.3 合规注意事项最后必须提一个非常重要的事做验证码逆向和自动化采集时一定要在平台的服务条款允许范围内操作。Temu这类平台其用户协议通常明确禁止未经授权的自动化访问和数据采集。如果你的行为影响到平台正常服务或者被认定为恶意攻击不仅可能被封号还可能面临法律风险。做技术研究、学习原理没问题但一旦投入商业用途请务必确保自己已经理解了相关的法律风险必要时要咨询专业的法律顾问。我是把验证码逆向当成一项技术挑战来研究的在自己搭建的测试环境中反复调试而不是直接拿去做大规模的商业采集。技术本身是中性的用在哪里、怎么用决定了它带来的价值还是风险。最后分享两个实用的小技巧第一个技巧是使用Chromium的远程调试协议来抽取JS运行时变量。有时候你光靠静态分析很难确定某个加密参数的值是怎么来的但如果你用Selenium或Puppeteer启动一个浏览器页面手动触发一次验证码流程然后通过远程调试协议直接读取页面里的全局变量很多疑问就能迎刃而解。比如某个加密用的secret key可能只有在运行时才被赋值到window对象的某个属性上。第二个技巧是写一个简单的验证码样本收集器。每次脚本遇到新的验证码类型时自动把背景图、滑块图、目标结果和最终的校验结果保存到一个目录里。积累几百条样本后你会发现不同时期验证码风格的变化规律对未来预测平台更新方向很有帮助。这个技巧救过我很多次因为有了历史样本平台一旦更新验证码样式我可以快速对比出哪些部分变了。做逆向这件事本质上是一个不断否定自己、又不断重构方案的过程。Temu验证码逆向折腾下来我最深的感觉是没有一劳永逸的方案只有不断迭代的适配能力。希望这篇分享能给你提供一些有价值的参考少走一些我已经踩过的弯路。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。