尧图精选

Python+Playwright实战:破解Shopee弧形滑块验证码的完整方案

🕒 发布时间:2026/9/20 13:19:50 📁 来源:尧图网络
最近好几个做Shopee的朋友跟我抱怨说现在平台的滑块验证码越来越难搞。以前那种直来直去的水平滑块已经很少见了现在换成了带弧度的弧形滑块拖快了不行拖慢了也不行轨迹稍微生硬一点就提示“验证失败”。我自己在自动化项目里也踩了不少坑前后折腾了几个星期总算是把PythonPlaywright这套流程跑通了顺手还接了影刀RPA做兜底。这篇文章把整个思路和代码都梳理出来给还在跟验证码死磕的朋友做个参考。先说清楚这里的“绕过”指的是通过合法的自动化手段完成滑块验证用于自动化测试、店铺运营提效、数据采集等合规场景。不是说去攻击平台的防护体系也不是鼓励大家做违规操作。平台的反爬机制也是在不断更新的本文提供的是当前可行的一种技术思路后续如果验证码策略调整需要顺着同样的思路去做适配。另外还要提醒一句任何自动化工具都会对账号安全产生影响本身就存在被平台风控的风险。在做之前一定要评估好账号价值别为了图省事把主账号搭进去。1. 验证码这件“小事”为什么能卡住自动化流程1.1 Shopee弧形滑块到底“难”在哪传统滑块验证码大多是水平方向的直线拖动从起点拖到缺口位置只要轨迹平滑、速度合理通过率就很高。但Shopee这类跨境电商平台用的弧形滑块设计逻辑完全不一样。弧形滑块的缺口不是在同一条水平线上而是沿着一条弧线分布。滑块初始位置在左下角缺口在右上方的弧形轨迹上。拖动的时候鼠标既要向右移动又要向上移动而且移动路径需要贴合弧线形状不能走直线斜穿过去。这对自动化脚本来说是个麻烦事——很多现成的滑块破解方案都是基于水平距离计算的遇到弧形就失灵了。更刁钻的是Shopee的滑块还会采集鼠标在拖动过程中的轨迹数据包括位移曲线、速度变化、停顿点、抖动幅度等。如果这些数据呈现出明显的机械化特征比如匀速直线移动、完全没有微小抖动、没有加速减速过程就会被判定为脚本操作。所以光是把滑块拖到正确位置还不够轨迹的拟人程度直接决定验证成败。我最早用影刀RPA的鼠标移动命令去拖试了很多次成功概率不到两成。后来换成Playwright模拟真实鼠标轨迹通过率才算稳定下来。1.2 为什么选PythonPlaywright而不是纯RPA影刀RPA这类工具的优势是上手快拖拽命令就能完成很多操作但它的鼠标轨迹模拟能力相对有限。RPA的“鼠标移动”命令本质上是把鼠标从A点移到B点中间没有太复杂的轨迹规划面对弧形滑块这种对轨迹有要求的验证码就很吃力。Playwright作为微软出品的自动化测试框架核心优势在于它可以通过CDP协议控制浏览器底层的输入事件模拟出来的鼠标移动、点击、键盘输入在浏览器看来跟真实用户几乎一样。同时Playwright支持自定义鼠标轨迹可以按任意坐标序列逐点移动这让模拟弧形轨迹成为可能。Python生态里还有OpenCV这种图像处理库可以做缺口定位。所以完整的技术路线是Playwright负责控制浏览器和模拟鼠标OpenCV负责识别缺口位置两者配合完成验证。影刀RPA则作为补充方案在Playwright方案失败或者不适合的场景下做兜底。这套组合还解决了另一个问题开发效率。Playwright的代码量不大核心逻辑几百行就能搞定而且调试起来很方便能看到每一步的截图。比起反复测试RPA的鼠标参数写代码可控性强得多。2. 动手前的准备环境、工具和项目结构2.1 Python环境与依赖库安装这一步没什么高深的但是容易踩坑尤其是Python环境没配好的同学。先确认一下自己的Python版本建议3.9以上太老版本对Playwright的支持不太好。用以下命令创建虚拟环境并安装依赖# 创建虚拟环境 python -m venv venv # 激活虚拟环境 # Windows下: venv\Scripts\activate # macOS/Linux下: source venv/bin/activate # 安装核心依赖 pip install playwright opencv-python numpy requests flask注意opencv-python这个包比较大下载可能比较慢。如果网络环境一般可以用国内镜像源pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-python安装完依赖之后还要执行Playwright的浏览器安装命令。这一步容易忽略很多人依赖装好了结果运行的时候报“Executable doesnt exist”之类的错误python -m playwright install chromium这里只装Chromium就够了不用把Firefox和WebKit都装上省时间也省磁盘空间。2.2 项目目录规划项目的结构建议这样搭逻辑清晰后续维护也方便shopee_slider/ ├── config.py # 配置文件存放URL、超时时间、阈值等 ├── detector.py # 缺口识别模块封装OpenCV相关逻辑 ├── trajectory.py # 轨迹生成模块生成拟人化的移动轨迹 ├── slider.py # 滑块操作核心逻辑Playwright控制 ├── server.py # Flask服务供影刀RPA调用 └── main.py # 直接运行入口用于测试调参模块化拆分的好处是每一部分都能单独测试。我在实际开发中缺口识别和轨迹生成就是分开调的改一个参数另一块完全不受影响。2.3 浏览器的启动参数配置Playwright启动浏览器时的参数配置很关键直接影响页面环境的真实性。以下是我项目中比较稳定的配置from playwright.sync_api import sync_playwright def create_browser(): playwright sync_playwright().start() browser playwright.chromium.launch( headlessFalse, # 一定要有头模式验证码识别需要看到页面 args[ --disable-blink-featuresAutomationControlled, # 关闭自动化控制标记 --no-sandbox, --disable-infobars, --window-size1280,800 ] ) context browser.new_context( viewport{width: 1280, height: 800}, user_agentMozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36, localezh-CN, ) # 移除webdriver属性降低被识别的概率 context.add_init_script(Object.defineProperty(navigator, webdriver, {get: () undefined})) page context.new_page() return playwright, browser, page--disable-blink-featuresAutomationControlled这个参数是去掉自动化控制标记的navigator.webdriver的初始脚本也是同理。这些设置本身没什么问题不过不同网站的检测方式不一样有些还会校验更多维度比如是否存在Chrome DevTools相关端口、字体渲染差异、Canvas指纹等。真遇到那种强度的检测这些手段就不够用了需要在别的层面想办法。3. 核心实现从识别缺口到模拟弧形轨迹3.1 元素定位与图片截取打开目标页面之后第一步是定位滑块和背景图片元素。Shopee的滑块验证码结构在不同区域可能有差异我在东南亚站点测试时常见的结构是背景图片一个img标签或canvas显示带缺口的背景图滑块按钮一个div元素内部包含可拖动的箭头或拼图块定位方式建议优先使用CSS选择器稳定性和可读性都比较好。拿不到稳定选择器的时候再用XPath兜底。def locate_captcha_elements(page): # 背景图元素 bg_img page.wait_for_selector(#captcha_bg_img, .captcha-background img, img[class*bg], timeout10000) # 滑块元素 slider page.wait_for_selector(#captcha_slider, .captcha-slider, div[class*slider], timeout10000) # 获取滑块的位置和尺寸 slider_box slider.bounding_box() if not slider_box: raise Exception(滑块元素没有绑定框无法定位) return bg_img, slider, slider_box这里有一个关键点获取元素坐标的时候Playwright的bounding_box()返回的是元素相对于视口的坐标这个坐标可以直接用于鼠标操作。但是如果页面有滚动或者缩放坐标会有偏差需要注意处理。3.2 用OpenCV识别缺口位置缺口识别是整个方案的核心环节。识别不准后面轨迹模拟得再像也没用。Shopee的弧形滑块缺口特征比较明显背景图被切掉一块缺口边缘有明显的亮度差异。用OpenCV做缺口定位常见有两种思路轮廓检测和模板匹配。模板匹配需要事先准备缺口图块作为模板问题在于每个验证码的缺口形状都不同模板不具备通用性。所以我用的是轮廓检测方案具体步骤截取背景图转为灰度图高斯模糊去噪用Canny边缘检测提取轮廓在滑块目标位置附近查找轮廓通过面积、形状筛选缺口以下是核心代码import cv2 import numpy as np def detect_gap(bg_img_bytes, slider_width80): 识别背景图中的缺口位置返回缺口中心坐标 # 将图片字节转成numpy数组 img_array np.frombuffer(bg_img_bytes, dtypenp.uint8) img cv2.imdecode(img_array, cv2.IMREAD_COLOR) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 高斯模糊减少噪点干扰 blurred cv2.GaussianBlur(gray, (5, 5), 0) # 边缘检测 edges cv2.Canny(blurred, 100, 200) # 轮廓查找 contours, _ cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 筛选轮廓在图片右半部分查找面积适中的轮廓 h, w edges.shape[:2] candidates [] for cnt in contours: x, y, cw, ch cv2.boundingRect(cnt) # 缺口的宽度通常在滑块宽度的1-2倍之间高度占图片高度的20%-40% if x w * 0.45 and slider_width * 0.6 cw slider_width * 2.5: if h * 0.15 ch h * 0.6: candidates.append((x cw // 2, y ch // 2, cw, ch)) if not candidates: # 兜底直接返回最大轮廓中心 if contours: largest max(contours, keycv2.contourArea) x, y, cw, ch cv2.boundingRect(largest) return x cw // 2, y ch // 2, cw, ch raise Exception(未找到缺口轮廓) # 返回最靠右的候选弧形缺口一般位于右上角区域 candidates.sort(keylambda c: c[0], reverseTrue) return candidates[0][0], candidates[0][1], candidates[0][2], candidates[0][3]这里有一个参数细节轮廓筛选的阈值x w * 0.45意思是只关注图片右半边的轮廓。因为弧形滑块的缺口整体偏右这样可以排除左边滑块起始区域的干扰。如果验证码样式变了这个阈值可能也得跟着调。实际识别完后建议在代码里加一步可视化调试把检测结果画出来看debug_img img.copy() cx, cy, cw, ch detect_gap(bg_bytes) cv2.rectangle(debug_img, (cx - cw // 2, cy - ch // 2), (cx cw // 2, cy ch // 2), (0, 0, 255), 2) cv2.imwrite(debug_gap.jpg, debug_img)这一步能省很多时间参数调没调对一眼就能看出来。3.3 弧形轨迹的数学建模识别出缺口位置之后光把鼠标水平移过去是不够的。回到之前说的问题滑块缺口不是水平方向的而是在弧线上。所以鼠标移动轨迹也要配合弧线形状。弧形轨迹的模拟我用的是三次贝塞尔曲线。贝塞尔曲线的好处是可以通过控制点决定曲线形状从而让轨迹看起来自然不像直线那样生硬。假设滑块起点坐标为(start_x, start_y)缺口中心坐标为(end_x, end_y)。正常直线移动是直接把鼠标从起点拉到终点而弧形需要的是一条向右上方延伸的曲线。控制点如何设置呢我试过几种方案最终比较稳定的是第一个控制点在起点右下方制造一个先下沉再上升的效果第二个控制点在终点附近让轨迹收拢计算公式import numpy as np def bezier_curve(start, end, control1, control2, steps50): 生成三次贝塞尔曲线上的点集 t np.linspace(0, 1, steps) points [] for i in range(steps): # 三次贝塞尔公式 x (1 - t[i])**3 * start[0] 3 * (1 - t[i])**2 * t[i] * control1[0] 3 * (1 - t[i]) * t[i]**2 * control2[0] t[i]**3 * end[0] y (1 - t[i])**3 * start[1] 3 * (1 - t[i])**2 * t[i] * control1[1] 3 * (1 - t[i]) * t[i]**2 * control2[1] t[i]**3 * end[1] points.append((x, y)) return points def generate_arc_trajectory(start, end, arc_height40): 生成弧形轨迹点列表 start: (x1, y1) 滑块起点 end: (x2, y2) 缺口中心 arc_height: 弧线隆起高度 dx end[0] - start[0] dy end[1] - start[1] # 控制点1位于起点右下方让轨迹先走一个下沉弧度 c1 (start[0] dx * 0.25, start[1] dy * 0.5 arc_height * 0.3) # 控制点2位于终点左上方让轨迹向上隆起 c2 (start[0] dx * 0.75, start[1] dy * 0.2 - arc_height * 0.8) return bezier_curve(start, end, c1, c2, steps60)这个arc_height参数控制曲线的隆起程度需要根据实际页面观察调整。页面弧线陡的就调大缓的就调小。我测试时一般取30到50之间具体情况得看截图判断。3.4 模拟拟人化拖动轨迹只是第一步有了弧形轨迹坐标点还不能直接按顺序拖过去。真人在拖滑块的时候手部动作会有很多微妙的变化一开始轻微加速中间有停顿快到终点时会减速找准位置过程中还会出现像素级的微小抖动。只把鼠标按坐标逐点移动如果不做速度变化和抖动模拟Playwright发出来的轨迹依然会被识别为机械操作。我封装了一个拖动函数逻辑是将轨迹点分成三段起始段加速、中间段稳定、收尾段减速校准每段设置不同的移动间隔时间在坐标点上叠加高斯噪声模拟手部微小抖动在收尾段插入一个短暂的停顿再松手核心代码import random import time def human_like_drag(page, slider_box, trajectory): 模拟人类拖拽滑块 # 滑块中心起点 start_x slider_box[x] slider_box[width] / 2 start_y slider_box[y] slider_box[height] / 2 # 鼠标移动到滑块位置并按下 page.mouse.move(start_x, start_y) page.mouse.down() # 分段设置不同的延时 total_points len(trajectory) split_1 int(total_points * 0.2) # 起始加速段 split_2 int(total_points * 0.7) # 中间匀速段 for i, (x, y) in enumerate(trajectory): # 叠加高斯抖动模拟手部微小移动 jitter_x random.gauss(0, 0.6) jitter_y random.gauss(0, 0.6) target_x x jitter_x target_y y jitter_y # 移动鼠标 page.mouse.move(target_x, target_y, steps1) # 根据阶段设置间隔时间 if i split_1: # 起始段逐步提速 interval 0.02 - 0.01 * (i / split_1) elif i split_2: # 中间段相对稳定 interval 0.008 random.uniform(0.002, 0.006) else: # 收尾段减速模拟微调 interval 0.015 random.uniform(0.01, 0.02) time.sleep(interval) # 松手前短暂停顿模拟确认位置 time.sleep(random.uniform(0.1, 0.25)) page.mouse.up()关于page.mouse.move()的steps参数官方文档说设置大于1时会插入中间事件。我这里固定为1配合手写的时间间隔对轨迹的控制更精细。如果完全依赖Playwright的steps模拟中间轨迹是由浏览器自动补的可控性差。3.5 如何验证轨迹是否拟人调轨迹参数的时候最怕的一件事验证码看起来通过了一两次但过一会儿又被风控了。这是典型的“假阳性”现象——你验证成功了但平台已经标记了你的行为异常后面可能触发更严格的验证。我自己的验证方法比较土但很有效连续使用轨迹生成器跑50次把每次生成的轨迹坐标和间隔时间记录下来用图表画出来看。画出轨迹曲线看有没有明显的机械化直线段画出速度曲线看加速减速是否平滑统计停顿点分布看停顿是不是每次都出现在固定的位置和时长如果50次轨迹的形状都差不多说明随机性不够需要增加随机因子。如果速度曲线很平滑但缺少突变说明间隔时间设置得过于均匀真人在拖动中偶尔会有加速到最高点再骤降的情况。这些细节不开发的人可能觉得吹毛求疵但真的决定了验证码的通过率。我之前用均匀间隔的轨迹通过率只有50%左右换成分段变速之后通过率稳定在80%以上。4. 影刀RPA接入让非程序员也能用这套方案4.1 为什么影刀RPA不能直接调Python影刀RPA虽然支持Python扩展但它的内置Python运行时和外部安装的Python环境是隔离的而且RPA脚本运行在独立的运行时环境中直接import playwright往往失败。更关键的是影刀RPA操作鼠标的方式是通过底层驱动控制跟Playwright的CDP协议不是一条路。两者的坐标体系、事件模型都不同没法在RPA里直接复用Playwright的鼠标轨迹逻辑。所以我的接线方案是用一个本地HTTP服务把识别和轨迹计算能力封装成API影刀RPA在需要验证的时候发起HTTP请求获取轨迹点然后用自身的鼠标移动命令按轨迹点执行。4.2 搭建本地识别服务在项目里加一个server.py用Flask起一个轻量服务暴露两个接口/detect接收背景图URL或Base64返回缺口坐标/trajectory接收起点和终点返回拟人化弧形轨迹点列表import base64 from flask import Flask, request, jsonify import requests app Flask(__name__) app.route(/detect, methods[POST]) def detect(): data request.get_json() url data.get(url) slider_width data.get(slider_width, 80) if url: resp requests.get(url) bg_bytes resp.content elif data.get(base64): bg_bytes base64.b64decode(data[base64].split(,)[-1]) else: return jsonify({error: 请输入图片url或base64}), 400 try: cx, cy, cw, ch detect_gap(bg_bytes, slider_width) return jsonify({cx: cx, cy: cy, cw: cw, ch: ch}) except Exception as e: return jsonify({error: str(e)}), 500 app.route(/trajectory, methods[POST]) def trajectory(): data request.get_json() start tuple(data[start]) # 格式: [x, y] end tuple(data[end]) # 格式: [x, y] points generate_arc_trajectory(start, end, arc_heightdata.get(arc_height, 40)) return jsonify({points: [{x: p[0], y: p[1]} for p in points]}) if __name__ __main__: app.run(host127.0.0.1, port5005, debugFalse)启动服务python server.py接口就挂在本地的5005端口上。影刀RPA和其他任何支持HTTP请求的程序都能调用不是只能给影刀用。4.3 影刀RPA侧的调用代码影刀RPA的Python脚本里用requests库调用本地服务拿到轨迹点后循环执行鼠标移动命令。影刀RPA的鼠标移动命令在不同版本里API略有差异大部分版本支持传入屏幕坐标。以下是一种通用写法import requests import time import random def get_trajectory(start_x, start_y, end_x, end_y): 请求本地轨迹服务 resp requests.post( http://127.0.0.1:5005/trajectory, json{ start: [start_x, start_y], end: [end_x, end_y], arc_height: 40 } ) if resp.status_code 200: return [(p[x], p[y]) for p in resp.json()[points]] raise Exception(轨迹服务请求失败) def move_slider_with_trajectory(trajectory): 按轨迹拖动滑块 # 第一个点按下鼠标 x, y trajectory[0] # 影刀中移动鼠标到指定坐标 Mouse.MoveTo(x, y) Mouse.ButtonDown() time.sleep(random.uniform(0.05, 0.1)) # 按轨迹逐点移动 for i in range(1, len(trajectory)): tx, ty trajectory[i] Mouse.MoveTo(tx, ty) # 间隔时间与Playwright方案一致 time.sleep(random.uniform(0.005, 0.02)) time.sleep(random.uniform(0.1, 0.2)) Mouse.ButtonUp()影刀里通过Mouse对象控制鼠标具体API不同版本有差异。如果你用的版本没有ButtonDown/ButtonUp可以试试Mouse.Down()和Mouse.Up()或者用“按住鼠标”和“释放鼠标”命令替代。实际操作的关键点坐标需要是屏幕坐标。影刀RPA中的坐标默认是屏幕绝对坐标不是浏览器内相对坐标。所以在调用前要通过影刀的“获取控件位置”命令拿到滑块在屏幕上的绝对坐标。轨迹点要平滑连接。影刀的Mouse.MoveTo本身有默认的移动时间如果直接把50个轨迹点发过去可能因为移动命令执行太快忽略中间点。我实测下来一次移动耗时越长效果越好。可以用Mouse.SetSpeed之类命令调整鼠标移动速度或者每隔几个轨迹点合并成一个移动批次。不要忽略抖动。轨迹服务里已经加了高斯抖动但如果影刀执行时发现明显跳变可以检查坐标是否为整数。浮点坐标在部分影刀版本中会被取整导致轨迹出现台阶状突变。这种情况可以在服务端把坐标round成整数但保留微小的浮点随机数做偏移。4.4 影刀RPA完整接入示例整个影刀流程可以这样编排用户手动或通过流程打开Shopee页面等待验证码出现截取背景图和滑块区域截图调用本地/detect接口获取缺口坐标获取滑块在屏幕上的绝对坐标调用本地/trajectory接口生成轨迹按轨迹执行鼠标拖拽检查验证码是否通过未通过则重置后重试关键步骤的影刀Python代码如下import requests import time def robot_do_slider(bg_image_path, slider_screen_x, slider_screen_y, gap_screen_x, gap_screen_y): 影刀主流程完成一次滑块验证 # 1. 识别缺口也可以直接传图片URL with open(bg_image_path, rb) as f: import base64 bg_b64 base64.b64encode(f.read()).decode() resp requests.post( http://127.0.0.1:5005/detect, json{base64: bg_b64} ) if resp.status_code ! 200: raise Exception(缺口识别失败) gap resp.json() center_x gap[cx] center_y gap[cy] # 2. 计算终点在屏幕上的绝对坐标 # 注意这里需要在影刀里获取背景图在屏幕上的起始坐标然后加上缺口偏移 end_x bg_screen_x center_x end_y bg_screen_y center_y # 3. 生成轨迹 traject_points get_trajectory(slider_screen_x, slider_screen_y, end_x, end_y) # 4. 执行拖动 move_slider_with_trajectory(traject_points) # 5. 等待验证结果 time.sleep(2) # 调用示例 robot_do_slider( bg_image_pathcaptcha_bg.png, slider_screen_x242, # 滑块在屏幕上的x坐标 slider_screen_y531, # 滑块在屏幕上的y坐标 bg_screen_x180, # 背景图左上角在屏幕上的x bg_screen_y400 # 背景图左上角在屏幕上的y )这套流程跑起来之后影刀就相当于有了一个“AI大脑”自己只负责执行识别和轨迹规划都交给Python服务处理。好处是识别算法改了不用动影刀流程只更新Python服务就行。5. 实际调优与常见问题排查5.1 缺口识别不准怎么办我碰到的第一个问题是OpenCV把背景图里的干扰元素当成了缺口返回的坐标偏了几十像素滑块拖过去之后位置对不上。排查方法先截图调试把识别结果画出来。这一步能区分是边缘检测问题还是轮廓筛选问题。Canny阈值调参。Canny(edges, 100, 200)的100和200需要根据图片明暗程度调整浅色背景可以降到50到150深色背景则提高。增加轮廓面积过滤条件。比如缺口宽度占背景图宽度的比例一般集中在8%到20%之间。根据你的验证码实际尺寸调整。备选方案如果边缘检测老是识别到干扰物可以把缺口附近的区域裁剪出来单独识别减少背景干扰。5.2 Playwright定位不到滑块元素Shopee验证码的HTML结构可能随页面变化CSS选择器失效很正常。遇到这种情况我一般用组合策略等一段时间再定位验证码如果还在加载中元素可能还没渲染完尝试多级选择器比如先定位弹窗容器再定位内部滑块用Playwright的page.query_selector_all()把所有元素都打印出来排查# 调试辅助打印所有div的class和id elements page.query_selector_all(div) for el in elements: cls el.get_attribute(class) or eid el.get_attribute(id) or if captcha in cls or slider in cls or verify in cls: print(fid{eid} class{cls})我遇到过最坑的一种情况页面套了多层Shadow DOM普通选择器根本定位不到内部元素。Playwright支持page.locator(cssselector).shadow()穿透Shadow DOM如果发现选择器能定位外层但取不到内部滑块可以试试这个办法。5.3 验证码拖完以后提示“拖动过快”这个提示通常是因为轨迹的速度变化不够拟人。真人拖动不会全程匀速更不会只花0.2秒从起点冲到终点。我建议关注两个数据总耗时一般控制在1.2到2.5秒之间具体看滑块移动距离。距离越长耗时越长。速度变化起始段要有加速过程从0开始逐渐加快收尾段要有明显的减速快到缺口时速度降到很低中间可以有轻微波动。如果验证码仍然提示“拖动过快”把间隔时间整体放大20%到30%再测试。调整的时候一次只改一个变量改多了就不知道是哪个参数起的作用了。5.4 验证码被刷新坐标失效Shopee会在验证失败或长时间未操作时刷新验证码背景图和缺口位置都会变。所以脚本要设计成循环结构操作前先获取当前验证码的背景图执行操作检查验证结果如果失败重新获取新验证码进入下一次循环Playwright的写法可以用page.wait_for_selector等待验证码刷新后的元素变更或者直接重新定位背景图元素再截一次图。不要复用上一次的坐标必挂。5.5 平台是否会自动检测Playwright现代网站的反自动化检测手段越来越多。除了传统的navigator.webdriver检测还可能检测浏览器窗口大小是否异常自动化窗口常常是固定值是否安装了某些自动化插件WebGL渲染器信息是否一致鼠标事件序列是否合理我的经验是设置一个和正常用户一致的User-Agent比如Windows桌面Chrome的UA使用有头模式不要用headlessTrue再配合前面的轨迹优化基本可以规避大部分常规检测。这里也说明一件事情验证码识别的本质是一场猫鼠游戏没有一劳永逸的方案对方更新策略你就得跟着调。5.6 如何处理验证码的重试策略即使轨迹优化得再好也没法保证100%一次通过。我自己的统计通过率在80%到90%之间剩下的10%需要重试。重试策略建议采用“指数退避”的思路第一次失败等1到2秒再重试第二次失败等3到5秒连续失败超过5次停30秒让风控冷静一下再继续。不要无脑快速重试否则触发二次验证难度会更高。import time retry_times 5 for attempt in range(retry_times): success try_verify(page) if success: break wait_time min(2 ** attempt, 15) time.sleep(wait_time) if not success: raise Exception(多次尝试滑块验证失败需要人工介入)如果连续多次失败我建议停止自动操作切换人工验证。这比把账号玩坏了划算得多。5.7 影刀RPA调用常见的坑影刀RPA接入后可能遇到这些情况坐标漂移不同机器的屏幕分辨率和缩放比例不同同一个Shadow坐标在不同机器上对应的屏幕坐标有差异导致滑块拖不到准确位置。解决方法是把轨迹点的比例信息传给RPA在RPA里根据当前屏幕和原始截图的比例做转换。鼠标移动被系统加速Windows系统默认开启了鼠标加速功能这会影响RPA控件模拟鼠标移动时的路径。可以在影刀执行前通过电脑设置关闭“提高指针精确度”或者至少保证测试和生产环境的设置一致。调用本地服务失败如果影刀和Python服务不在一台机器上需要把127.0.0.1改成实际服务机器的IP同时放通防火墙端口。我建议把服务部署在局域网内的固定机器上方便多台RPA同时调用。6. 整个方案的边界与注意事项讲到这里技术方案基本完整了但还是要多说几句负责任的话。这类自动化操作一定是有风险的。Shopee的风控体系不只是验证码本身还包括账号行为画像、设备指纹、操作频率等多维度的检测。如果你用这套方案高频操作大量账号即使验证码全过账号也可能因为其他维度的异常被限制。我可以给出的建议是控制操作频率。不要为了跑数据就24小时不间歇正常人不会有这种操作行为。控制账号数量。运营多个账号时要让操作行为保持多样性别用完全相同的代码跑所有账号。尽量模拟真实业务流程。比如在商品编辑、订单处理这些真实操作场景中绕过验证码而不是让整个行为看起来就是机器人在验证码上反复拖拽。做好异常兜底。脚本要能识别“需要人工介入”的场景别把账号试死了才停。另外如果你只是做技术研究和学习强烈建议在自己开发的测试环境里模拟不要直接打生产环境的站点。用真实平台练手既是合规风险也容易误导你对方案有效性的判断——毕竟生产环境的验证码类型和强度跟开发环境完全不是一个量级。最后说一句我的亲身体会滑块验证码这个领域方案永远在更新今天好用的思路明天可能就失效了。与其追求一个能永久跑的脚本不如把“识别-规划-执行-重试”这套框架吃透这样验证码怎么变你都能用同样的思路快速适配。这套方案跑通之后我自己最大的收获不是代码本身而是对自动化操作的“拟人化”有了更深的体感——技术上解决一个问题往往不只是找到一段能跑的代码而是理解对面系统为什么这样设计然后把交互做细。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →