注册 登录
发贴工具
查看: 4|回复: 0
打印 上一主题 下一主题

[24小时收录超级好的网站] 元宝截图B站验证码示例测试

[复制链接]

2584

主题

2632

帖子

1万

积分

积分
15680
跳转到指定楼层
楼主
元宝截图B站验证码示例测试
元宝截图B站验证码示例测试 群发软件发帖工具

  1. // AIWROK 自动化流程:截图B站验证码 → 启动元宝 → 发送截图询问拖动距离 → 采集回答 → 切回B站拖动滑块
  2. // 包名:com.tencent.hunyuan.app.chat(元宝)
  3. //
  4. // 使用说明:
  5. //   1. 在B站验证码页面运行脚本
  6. //   2. 脚本自动截图并发送给元宝识别
  7. //   3. 解析元宝返回的拖动距离,切回B站拖动滑块

  8. print.log("===== 元宝识别验证码拖动B站流程启动 =====");
  9. print.time();

  10. // ========== 配置区 ==========
  11. var 元宝包名 = "com.tencent.hunyuan.app.chat";
  12. var B站包名 = "tv.danmaku.bili";
  13. var 截图保存路径 = "/sdcard/验证码截图.png";

  14. var 等待回答超时秒 = 20;
  15. var 回答输出等待秒 = 5;
  16. var 滑块校准系数 = 1.0;

  17. var 提问话术 = "请帮我分析这张图片,告诉我左边的方块需要向右移动多少像素才能和右边的缺口对齐,只输出数字";

  18. // ========== 获取设备信息 ==========
  19. var 屏幕宽 = screen.getScreenWidth();
  20. var 屏幕高 = screen.getScreenHeight();
  21. var 验证码滑块距离 = null;
  22. print.log("屏幕尺寸:" + 屏幕宽 + " x " + 屏幕高);
  23. print.log("代理状态:" + (agent.isOpen() ? "已开启" : "未开启"));

  24. // ========== 工具函数 ==========

  25. function 获取UI() {
  26.     var xml = agent.getXml();
  27.     return "" + xml;
  28. }

  29. function 字符串长度(s) {
  30.     var str = "" + s;
  31.     return str.length;
  32. }

  33. function 解码HTML实体(s) {
  34.     var str = "" + s;
  35.     str = str.replace(/
  36. /g, "\n");
  37.     str = str.replace(/
  38. /g, "\r");
  39.     str = str.replace(/        /g, "\t");
  40.     str = str.replace(/'/g, "'");
  41.     str = str.replace(/"/g, '"');
  42.     str = str.replace(/"/g, '"');
  43.     str = str.replace(/'/g, "'");
  44.     str = str.replace(/&/g, "&");
  45.     str = str.replace(/</g, "<");
  46.     str = str.replace(/>/g, ">");
  47.     return str;
  48. }

  49. function 采集AI回答列表(xml) {
  50.     var xmlStr = "" + xml;
  51.     var 回答列表 = [];

  52.     var messageLinearlayoutPattern = /<node[^>]*?resource-id="[^"]*?message_linearlayout"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  53.     var lineMatch;
  54.    
  55.     while ((lineMatch = messageLinearlayoutPattern.exec(xmlStr)) !== null) {
  56.         var lineStart = lineMatch.index;
  57.         var lineEnd = xmlStr.indexOf('/node>', lineStart);
  58.         if (lineEnd === -1) lineEnd = xmlStr.length;
  59.         var lineContent = xmlStr.substring(lineStart, lineEnd);
  60.         
  61.         if (lineContent.indexOf('chats_message_dtmp_answer_container') !== -1) {
  62.             var textViewPattern = /<node[^>]*?text="([^"]+)"[^>]*?class="android\.widget\.TextView"[^>]*?\/?>/g;
  63.             var tvMatch;
  64.             while ((tvMatch = textViewPattern.exec(lineContent)) !== null) {
  65.                 if (tvMatch[1] && 字符串长度(tvMatch[1]) > 1) {
  66.                     var 原始文本 = tvMatch[1];
  67.                     var 解码文本 = 解码HTML实体(原始文本);
  68.                     if (!回答列表.includes(解码文本)) {
  69.                         回答列表.push(解码文本);
  70.                         print.log("✓ 在回答容器中找到文本: '" + 解码文本 + "'");
  71.                     }
  72.                 }
  73.             }
  74.         }
  75.     }
  76.    
  77.     if (回答列表.length === 0) {
  78.         print.log("⚠ 未找到AI回答节点");
  79.     } else {
  80.         print.log("✓ 采集到" + 回答列表.length + "条AI回答");
  81.     }

  82.     return 回答列表;
  83. }

  84. function 获取当前最后AI回答(xml) {
  85.     var 回答列表 = 采集AI回答列表(xml);
  86.     if (回答列表.length === 0) return "";
  87.     return 回答列表[回答列表.length - 1];
  88. }

  89. function 全屏截图(保存路径) {
  90.     try {
  91.         var result = agent.shell("screencap -p " + 保存路径);
  92.         print.log("✓ 截图命令执行:" + result);
  93.         
  94.         var lsResult = agent.shell("ls -la " + 保存路径);
  95.         print.log("✓ 截图文件检查:" + lsResult);
  96.         
  97.         return true;
  98.     } catch (e) {
  99.         print.log("⚠ 截图失败:" + e.message);
  100.         return false;
  101.     }
  102. }

  103. function 查找输入框中心(xml) {
  104.     var xmlStr = "" + xml;
  105.    
  106.     var inputIdx = xmlStr.indexOf('edConversationInput');
  107.     if (inputIdx === -1) {
  108.         inputIdx = xmlStr.indexOf('text="发消息或按住说话..."');
  109.     }
  110.     if (inputIdx === -1) {
  111.         inputIdx = xmlStr.indexOf('class="android.widget.EditText"');
  112.     }
  113.    
  114.     if (inputIdx !== -1) {
  115.         var 段 = xmlStr.substring(inputIdx);
  116.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  117.         if (m) {
  118.             var x1 = parseInt(m[1]);
  119.             var y1 = parseInt(m[2]);
  120.             var x2 = parseInt(m[3]);
  121.             var y2 = parseInt(m[4]);
  122.             print.log("✓ 输入框定位:bounds=[" + x1 + "," + y1 + "][" + x2 + "," + y2 + "]");
  123.             return {
  124.                 x: (x1 + x2) / 2,
  125.                 y: (y1 + y2) / 2
  126.             };
  127.         }
  128.     }

  129.     print.log("⚠ 未找到输入框,使用兜底坐标");
  130.     return {
  131.         x: 屏幕宽 * 0.4,
  132.         y: 屏幕高 * 0.92
  133.     };
  134. }

  135. function 查找加号按钮(xml) {
  136.     var xmlStr = "" + xml;
  137.    
  138.     var plusIdx = xmlStr.indexOf('flConversationInputPlus');
  139.     if (plusIdx !== -1) {
  140.         var 段 = xmlStr.substring(plusIdx);
  141.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  142.         if (m) {
  143.             var x = (parseInt(m[1]) + parseInt(m[3])) / 2;
  144.             var y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  145.             print.log("✓ 加号按钮定位:flConversationInputPlus,坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  146.             return { x: x, y: y };
  147.         }
  148.     }

  149.     var cvPlusIdx = xmlStr.indexOf('cv_chat_input_plus');
  150.     if (cvPlusIdx !== -1) {
  151.         var 段2 = xmlStr.substring(cvPlusIdx);
  152.         var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  153.         if (m2) {
  154.             var x = (parseInt(m2[1]) + parseInt(m2[3])) / 2;
  155.             var y = (parseInt(m2[2]) + parseInt(m2[4])) / 2;
  156.             print.log("✓ 加号按钮定位:cv_chat_input_plus,坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  157.             return { x: x, y: y };
  158.         }
  159.     }

  160.     var 输入框 = 查找输入框中心(xml);
  161.     if (输入框) {
  162.         var 预估X = 屏幕宽 * 0.92;
  163.         var 预估Y = 输入框.y;
  164.         print.log("⚠ 未找到加号按钮,使用输入框右侧兜底坐标(" + Math.round(预估X) + "," + Math.round(预估Y) + ")");
  165.         return { x: 预估X, y: 预估Y };
  166.     }

  167.     print.log("⚠ 加号按钮使用屏幕右侧底部兜底坐标");
  168.     return {
  169.         x: 屏幕宽 * 0.92,
  170.         y: 屏幕高 * 0.92
  171.     };
  172. }

  173. function 粘贴文本(文本) {
  174.     try {
  175.         Clipboard.copy("" + 文本);
  176.     } catch (e) {
  177.         print.log("⚠ Clipboard.copy 失败:" + e.message);
  178.     }
  179.     sleep.millisecond(毫秒 = 300);

  180.     try {
  181.         agent.shell("service call clipboard 3 i32 1 s16 '" + 文本 + "' i32 0");
  182.     } catch (e2) {
  183.         // 忽略错误
  184.     }
  185.     sleep.millisecond(毫秒 = 300);

  186.     agent.shell("input keyevent 279");
  187.     sleep.second(秒 = 1);
  188.     print.log("✓ 已粘贴文本:" + 文本);
  189. }

  190. function 查找相册选项(xml) {
  191.     var xmlStr = "" + xml;
  192.    
  193.     var text关键词 = ["相册", "图片", "照片", "所有照片", "从相册选择", "选择图片"];
  194.     for (var i = 0; i < text关键词.length; i++) {
  195.         var kw = text关键词[i];
  196.         var idx = xmlStr.indexOf('text="' + kw + '"');
  197.         if (idx !== -1) {
  198.             var 段 = xmlStr.substring(idx);
  199.             var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  200.             if (m) {
  201.                 print.log("✓ 相册选项定位:text=" + kw);
  202.                 return {
  203.                     x: (parseInt(m[1]) + parseInt(m[3])) / 2,
  204.                     y: (parseInt(m[2]) + parseInt(m[4])) / 2
  205.                 };
  206.             }
  207.         }
  208.     }

  209.     var desc关键词 = ["相册", "图片", "照片"];
  210.     for (var j = 0; j < desc关键词.length; j++) {
  211.         var kw2 = desc关键词[j];
  212.         var idx2 = xmlStr.indexOf('content-desc="' + kw2 + '"');
  213.         if (idx2 !== -1) {
  214.             var 段2 = xmlStr.substring(idx2);
  215.             var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  216.             if (m2) {
  217.                 print.log("✓ 相册选项定位:content-desc=" + kw2);
  218.                 return {
  219.                     x: (parseInt(m2[1]) + parseInt(m2[3])) / 2,
  220.                     y: (parseInt(m2[2]) + parseInt(m2[4])) / 2
  221.                 };
  222.             }
  223.         }
  224.     }

  225.     return null;
  226. }

  227. function 是否在系统相册页面(xml) {
  228.     var xmlStr = "" + xml;
  229.    
  230.     var packageMatch = xmlStr.match(/package="([^"]+)"/);
  231.     var 当前包名 = packageMatch ? packageMatch[1] : "";
  232.     if (当前包名 && 当前包名 !== 元宝包名) {
  233.         print.log("✓ 检测到系统相册页面,包名:" + 当前包名);
  234.         return true;
  235.     }
  236.    
  237.     var gallery关键词 = ["最近", "图库", "Camera", "所有图片", "照片", "相册", "All photos", "Photos"];
  238.     for (var i = 0; i < gallery关键词.length; i++) {
  239.         if (xmlStr.indexOf('text="' + gallery关键词[i] + '"') !== -1 ||
  240.             xmlStr.indexOf('content-desc="' + gallery关键词[i] + '"') !== -1) {
  241.             var 有聊天输入 = xmlStr.indexOf("edConversationInput") !== -1;
  242.             if (!有聊天输入) {
  243.                 print.log("✓ 检测到相册页面(关键词:" + gallery关键词[i] + ")");
  244.                 return true;
  245.             }
  246.         }
  247.     }
  248.    
  249.     var 有图片文件 = xmlStr.indexOf('.png"') !== -1 || xmlStr.indexOf('.jpg"') !== -1 ||
  250.                      xmlStr.indexOf('.jpeg"') !== -1 || xmlStr.indexOf('.gif"') !== -1;
  251.     var 有选择按钮 = xmlStr.indexOf('text="选择"') !== -1;
  252.     var 有聊天输入2 = xmlStr.indexOf("edConversationInput") !== -1;
  253.     var 有聊天列表 = xmlStr.indexOf("chat_recycler_view") !== -1;
  254.    
  255.     if (有图片文件 && 有选择按钮 && !有聊天输入2 && !有聊天列表) {
  256.         print.log("✓ 检测到相册页面(元宝ComposeView,有图片文件和选择按钮)");
  257.         return true;
  258.     }
  259.    
  260.     return false;
  261. }

  262. function 是否在图片预览页面(xml) {
  263.     var xmlStr = "" + xml;
  264.     if (xmlStr.indexOf('text="完成"') !== -1 || xmlStr.indexOf('text="发送"') !== -1) {
  265.         return true;
  266.     }
  267.     if (xmlStr.indexOf('content-desc="完成"') !== -1 || xmlStr.indexOf('content-desc="发送"') !== -1) {
  268.         return true;
  269.     }
  270.     return false;
  271. }

  272. function 查找图片预览确认按钮(xml) {
  273.     var xmlStr = "" + xml;
  274.    
  275.     var 关键词 = ["完成", "发送", "确认"];
  276.     for (var i = 0; i < 关键词.length; i++) {
  277.         var kw = 关键词[i];
  278.         var textIdx = xmlStr.indexOf('text="' + kw + '"');
  279.         if (textIdx !== -1) {
  280.             var 段 = xmlStr.substring(textIdx);
  281.             var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  282.             if (m) {
  283.                 var x = (parseInt(m[1]) + parseInt(m[3])) / 2;
  284.                 var y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  285.                 print.log("✓ 图片预览确认按钮定位:text=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  286.                 return { x: x, y: y };
  287.             }
  288.         }
  289.     }
  290.    
  291.     for (var j = 0; j < 关键词.length; j++) {
  292.         var kw2 = 关键词[j];
  293.         var descIdx = xmlStr.indexOf('content-desc="' + kw2 + '"');
  294.         if (descIdx !== -1) {
  295.             var 段2 = xmlStr.substring(descIdx);
  296.             var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  297.             if (m2) {
  298.                 var x = (parseInt(m2[1]) + parseInt(m2[3])) / 2;
  299.                 var y = (parseInt(m2[2]) + parseInt(m2[4])) / 2;
  300.                 print.log("✓ 图片预览确认按钮定位:content-desc=" + kw2 + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  301.                 return { x: x, y: y };
  302.             }
  303.         }
  304.     }
  305.    
  306.     print.log("⚠ 图片预览确认按钮使用兜底坐标(底部中间)");
  307.     return { x: 屏幕宽 * 0.5, y: 屏幕高 * 0.92 };
  308. }

  309. function 查找相册选择按钮(xml) {
  310.     var xmlStr = "" + xml;
  311.    
  312.     var 关键词列表 = ["选择", "完成", "确认", "发送", "确定"];
  313.     for (var i = 0; i < 关键词列表.length; i++) {
  314.         var kw = 关键词列表[i];
  315.         
  316.         var textPattern = new RegExp('text="' + kw + '[^"]*"[^>]*?bounds="\\[(\\d+),(\\d+)\\]\\[(\\d+),(\\d+)\\]"', 'gi');
  317.         var textMatch = textPattern.exec(xmlStr);
  318.         if (textMatch) {
  319.             var x = (parseInt(textMatch[1]) + parseInt(textMatch[3])) / 2;
  320.             var y = (parseInt(textMatch[2]) + parseInt(textMatch[4])) / 2;
  321.             print.log("✓ 相册选择按钮定位:text=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  322.             return { x: x, y: y };
  323.         }
  324.         
  325.         var descIdx = xmlStr.indexOf('content-desc="' + kw + '"');
  326.         if (descIdx !== -1) {
  327.             var 段2 = xmlStr.substring(descIdx);
  328.             var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  329.             if (m2) {
  330.                 var x = (parseInt(m2[1]) + parseInt(m2[3])) / 2;
  331.                 var y = (parseInt(m2[2]) + parseInt(m2[4])) / 2;
  332.                 print.log("✓ 相册选择按钮定位:content-desc=" + kw + ",坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  333.                 return { x: x, y: y };
  334.             }
  335.         }
  336.     }
  337.    
  338.     var bottomButtonPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  339.     var bottomMatch;
  340.     var 底部按钮列表 = [];
  341.     while ((bottomMatch = bottomButtonPattern.exec(xmlStr)) !== null) {
  342.         var bx1 = parseInt(bottomMatch[1]);
  343.         var by1 = parseInt(bottomMatch[2]);
  344.         var bx2 = parseInt(bottomMatch[3]);
  345.         var by2 = parseInt(bottomMatch[4]);
  346.         if (by1 >= 屏幕高 * 0.85) {
  347.             底部按钮列表.push({ x: (bx1 + bx2) / 2, y: (by1 + by2) / 2 });
  348.         }
  349.     }
  350.    
  351.     if (底部按钮列表.length > 0) {
  352.         底部按钮列表.sort(function(a, b) { return b.x - a.x; });
  353.         var 最右边按钮 = 底部按钮列表[0];
  354.         print.log("✓ 相册选择按钮定位:底部最右边按钮,坐标(" + Math.round(最右边按钮.x) + "," + Math.round(最右边按钮.y) + ")");
  355.         return { x: 最右边按钮.x, y: 最右边按钮.y };
  356.     }
  357.    
  358.     print.log("⚠ 相册选择按钮使用兜底坐标(底部)");
  359.     return { x: 屏幕宽 * 0.78, y: 屏幕高 * 0.92 };
  360. }

  361. function 查找第一张图片(xml) {
  362.     var xmlStr = "" + xml;
  363.    
  364.     if (是否在系统相册页面(xmlStr)) {
  365.         agent.shell("echo '" + xmlStr.substring(0, 5000) + "' > /sdcard/相册UI_dump.xml");
  366.         print.log("✓ 已保存相册UI XML到/sdcard/相册UI_dump.xml");
  367.         
  368.         var nafPattern = /<node[^>]*?NAF="true"[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  369.         var nafMatch;
  370.         var NAF小圆点列表 = [];
  371.         
  372.         while ((nafMatch = nafPattern.exec(xmlStr)) !== null) {
  373.             var nx1 = parseInt(nafMatch[1]);
  374.             var ny1 = parseInt(nafMatch[2]);
  375.             var nx2 = parseInt(nafMatch[3]);
  376.             var ny2 = parseInt(nafMatch[4]);
  377.             var nw = nx2 - nx1;
  378.             var nh = ny2 - ny1;
  379.             
  380.             if (nw >= 50 && nw <= 300 && nh >= 50 && nh <= 300) {
  381.                 if (ny1 >= 400 && ny2 <= 屏幕高 - 400) {
  382.                     NAF小圆点列表.push({ x1: nx1, y1: ny1, x2: nx2, y2: ny2, x: (nx1 + nx2) / 2, y: (ny1 + ny2) / 2 });
  383.                 }
  384.             }
  385.         }
  386.         
  387.         if (NAF小圆点列表.length > 0) {
  388.             NAF小圆点列表.sort(function(a, b) {
  389.                 if (a.y1 !== b.y1) return a.y1 - b.y1;
  390.                 return a.x1 - b.x1;
  391.             });
  392.             var 选中小圆点 = NAF小圆点列表[0];
  393.             print.log("✓ ComposeView找到NAF小圆点选择框:坐标(" + Math.round(选中小圆点.x) + "," + Math.round(选中小圆点.y) + "),bounds=[" + 选中小圆点.x1 + "," + 选中小圆点.y1 + "][" + 选中小圆点.x2 + "," + 选中小圆点.y2 + "]");
  394.             return { x: 选中小圆点.x, y: 选中小圆点.y };
  395.         }
  396.         
  397.         var imageDescPattern = /<node[^>]*?content-desc="([^"]+\.(png|jpg|jpeg|gif))"[^>]*?class="android\.view\.View"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/gi;
  398.         var imgMatch;
  399.         var 图片节点列表 = [];
  400.         
  401.         while ((imgMatch = imageDescPattern.exec(xmlStr)) !== null) {
  402.             var 文件名 = imgMatch[1];
  403.             var ix1 = parseInt(imgMatch[3]);
  404.             var iy1 = parseInt(imgMatch[4]);
  405.             var ix2 = parseInt(imgMatch[5]);
  406.             var iy2 = parseInt(imgMatch[6]);
  407.             var iw = ix2 - ix1;
  408.             var ih = iy2 - iy1;
  409.             
  410.             if (iw >= 100 && ih >= 100) {
  411.                 图片节点列表.push({ 文件名: 文件名, x1: ix1, y1: iy1, x2: ix2, y2: iy2, w: iw, h: ih });
  412.             }
  413.         }
  414.         
  415.         if (图片节点列表.length > 0) {
  416.             图片节点列表.sort(function(a, b) {
  417.                 if (a.y1 !== b.y1) return a.y1 - b.y1;
  418.                 return a.x1 - b.x1;
  419.             });
  420.             var 第一张图片 = 图片节点列表[0];
  421.             print.log("✓ 找到图片:" + 第一张图片.文件名 + ",bounds=[" + 第一张图片.x1 + "," + 第一张图片.y1 + "][" + 第一张图片.x2 + "," + 第一张图片.y2 + "]");
  422.             
  423.             var 选择框X = 第一张图片.x1 + 第一张图片.w * 0.77;
  424.             var 选择框Y = 第一张图片.y1 + 第一张图片.h * 0.24;
  425.             print.log("✓ 计算小圆点选择框坐标:(" + Math.round(选择框X) + "," + Math.round(选择框Y) + ")");
  426.             return { x: 选择框X, y: 选择框Y };
  427.         }
  428.         
  429.         var clickableViewPattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  430.         var clickMatch;
  431.         var 可点击区域 = [];
  432.         while ((clickMatch = clickableViewPattern.exec(xmlStr)) !== null) {
  433.             var cx1 = parseInt(clickMatch[1]);
  434.             var cy1 = parseInt(clickMatch[2]);
  435.             var cx2 = parseInt(clickMatch[3]);
  436.             var cy2 = parseInt(clickMatch[4]);
  437.             var cw = cx2 - cx1;
  438.             var ch = cy2 - cy1;
  439.             可点击区域.push({ x1: cx1, y1: cy1, x2: cx2, y2: cy2, w: cw, h: ch, x: (cx1 + cx2) / 2, y: (cy1 + cy2) / 2 });
  440.         }
  441.         
  442.         var 图片区域内可点击 = [];
  443.         for (var k = 0; k < 可点击区域.length; k++) {
  444.             var item = 可点击区域[k];
  445.             if (item.y >= 400 && item.y <= 屏幕高 - 400) {
  446.                 图片区域内可点击.push(item);
  447.             }
  448.         }
  449.         
  450.         if (图片区域内可点击.length > 0) {
  451.             图片区域内可点击.sort(function(a, b) {
  452.                 if (a.y !== b.y) return a.y - b.y;
  453.                 return a.x - b.x;
  454.             });
  455.             var 第一个可点击 = 图片区域内可点击[0];
  456.             print.log("✓ ComposeView图片区域内第一个可点击元素:坐标(" + Math.round(第一个可点击.x) + "," + Math.round(第一个可点击.y) + ")");
  457.             return { x: 第一个可点击.x, y: 第一个可点击.y };
  458.         }

  459.         print.log("⚠ 系统相册未找到图片,输出调试信息:");
  460.         print.log("  当前包名:" + xmlStr.match(/package="([^"]+)"/)[1]);
  461.         print.log("  XML前1000字符:" + xmlStr.substring(0, 1000));
  462.         print.log("  NAF小圆点数量:" + NAF小圆点列表.length);
  463.         print.log("  图片节点数量:" + 图片节点列表.length);
  464.         
  465.         var allImgViews = xmlStr.match(/class="android\.widget\.ImageView"/g);
  466.         print.log("  全部ImageView数量:" + (allImgViews ? allImgViews.length : 0));
  467.         
  468.         return { x: 屏幕宽 * 0.25, y: 屏幕高 * 0.3 };
  469.     }

  470.     var rvPattern = /<node[^>]*?class="androidx\.recyclerview\.widget\.RecyclerView"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  471.     var rvMatch;
  472.     var 图片列表区域 = null;

  473.     while ((rvMatch = rvPattern.exec(xmlStr)) !== null) {
  474.         var rx1 = parseInt(rvMatch[1]);
  475.         var ry1 = parseInt(rvMatch[2]);
  476.         var rx2 = parseInt(rvMatch[3]);
  477.         var ry2 = parseInt(rvMatch[4]);
  478.         var 高度 = ry2 - ry1;

  479.         if (ry1 > 屏幕高 * 0.7 && 高度 > 300) {
  480.             图片列表区域 = {x1: rx1, y1: ry1, x2: rx2, y2: ry2};
  481.             print.log("✓ 找到底部图片列表RecyclerView:[" + rx1 + "," + ry1 + "][" + rx2 + "," + ry2 + "]");
  482.             break;
  483.         }
  484.     }

  485.     if (图片列表区域) {
  486.         var imgPattern = /<node[^>]*?class="android\.widget\.ImageView"[^>]*?\/?>/g;
  487.         var imgMatch;
  488.         var 候选 = [];
  489.         while ((imgMatch = imgPattern.exec(xmlStr)) !== null) {
  490.             var imgNode = imgMatch[0];
  491.             var boundsMatch = imgNode.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  492.             if (!boundsMatch) continue;
  493.             var ix1 = parseInt(boundsMatch[1]);
  494.             var iy1 = parseInt(boundsMatch[2]);
  495.             var ix2 = parseInt(boundsMatch[3]);
  496.             var iy2 = parseInt(boundsMatch[4]);
  497.             var iw = ix2 - ix1;
  498.             var ih = iy2 - iy1;

  499.             var 在区域内 = (ix1 >= 图片列表区域.x1 && ix2 <= 图片列表区域.x2 &&
  500.                             iy1 >= 图片列表区域.y1 && iy2 <= 图片列表区域.y2);
  501.             var 是大图 = (iw > 100 && ih > 100);

  502.             if (在区域内 && 是大图) {
  503.                 候选.push({
  504.                     x: (ix1 + ix2) / 2,
  505.                     y: (iy1 + iy2) / 2,
  506.                     y1: iy1,
  507.                     x1: ix1
  508.                 });
  509.             }
  510.         }

  511.         if (候选.length > 0) {
  512.             候选.sort(function(a, b) {
  513.                 if (a.y1 !== b.y1) return a.y1 - b.y1;
  514.                 return a.x1 - b.x1;
  515.             });
  516.             var 选中 = 候选[0];
  517.             print.log("✓ 第一张图片定位:底部图片列表内的ImageView,坐标(" + Math.round(选中.x) + "," + Math.round(选中.y) + ")");
  518.             return { x: 选中.x, y: 选中.y };
  519.         }
  520.     }

  521.     var imgPattern2 = /<node[^>]*?class="android\.widget\.ImageView"[^>]*?\/?>/g;
  522.     var imgMatch2;
  523.     var 候选2 = [];
  524.     while ((imgMatch2 = imgPattern2.exec(xmlStr)) !== null) {
  525.         var imgNode = imgMatch2[0];
  526.         var boundsMatch = imgNode.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  527.         if (!boundsMatch) continue;
  528.         var ix1 = parseInt(boundsMatch[1]);
  529.         var iy1 = parseInt(boundsMatch[2]);
  530.         var ix2 = parseInt(boundsMatch[3]);
  531.         var iy2 = parseInt(boundsMatch[4]);
  532.         var iw = ix2 - ix1;
  533.         var ih = iy2 - iy1;

  534.         if (iy1 > 屏幕高 * 0.7 && iw > 100 && ih > 100) {
  535.             候选2.push({
  536.                 x: (ix1 + ix2) / 2,
  537.                 y: (iy1 + iy2) / 2,
  538.                 y1: iy1,
  539.                 x1: ix1
  540.             });
  541.         }
  542.     }

  543.     if (候选2.length > 0) {
  544.         候选2.sort(function(a, b) {
  545.             if (a.y1 !== b.y1) return a.y1 - b.y1;
  546.             return a.x1 - b.x1;
  547.         });
  548.         var 选中2 = 候选2[0];
  549.         print.log("✓ 第一张图片定位:底部区域ImageView,坐标(" + Math.round(选中2.x) + "," + Math.round(选中2.y) + ")");
  550.         return { x: 选中2.x, y: 选中2.y };
  551.     }

  552.     print.log("⚠ 未找到图片,使用兜底坐标(底部第一行第一列)");
  553.     return { x: 屏幕宽 * 0.15, y: 屏幕高 * 0.85 };
  554. }

  555. function 查找发送按钮中心(xml) {
  556.     var xmlStr = "" + xml;

  557.     var sendTextIdx = xmlStr.indexOf('text="发送"');
  558.     if (sendTextIdx !== -1) {
  559.         var 段 = xmlStr.substring(sendTextIdx);
  560.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  561.         if (m) {
  562.             print.log("✓ 发送按钮定位:文本匹配");
  563.             return {
  564.                 x: (parseInt(m[1]) + parseInt(m[3])) / 2,
  565.                 y: (parseInt(m[2]) + parseInt(m[4])) / 2
  566.             };
  567.         }
  568.     }

  569.     var inputIdx = xmlStr.indexOf('edConversationInput');
  570.     if (inputIdx !== -1) {
  571.         var 输入框段 = xmlStr.substring(inputIdx);
  572.         var 输入框边界 = 输入框段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  573.         if (输入框边界) {
  574.             var 输入框信息 = {
  575.                 x1: parseInt(输入框边界[1]),
  576.                 y1: parseInt(输入框边界[2]),
  577.                 x2: parseInt(输入框边界[3]),
  578.                 y2: parseInt(输入框边界[4]),
  579.                 centerY: (parseInt(输入框边界[2]) + parseInt(输入框边界[4])) / 2
  580.             };

  581.             var clickablePattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*?\/?>/g;
  582.             var clickMatch;
  583.             var candidates = [];

  584.             while ((clickMatch = clickablePattern.exec(xmlStr)) !== null) {
  585.                 var cx1 = parseInt(clickMatch[1]);
  586.                 var cy1 = parseInt(clickMatch[2]);
  587.                 var cx2 = parseInt(clickMatch[3]);
  588.                 var cy2 = parseInt(clickMatch[4]);
  589.                 var cw = cx2 - cx1;
  590.                 var ch = cy2 - cy1;

  591.                 var 是小按钮 = (cw < 300 && ch < 300);
  592.                 var 在输入框右侧 = (cx1 > 输入框信息.x2 - 100);
  593.                 var 在输入框水平行 = (cy1 >= 输入框信息.y1 - 100 && cy1 <= 输入框信息.y2 + 100);

  594.                 if (是小按钮 && 在输入框右侧 && 在输入框水平行) {
  595.                     candidates.push({
  596.                         x1: cx1, y1: cy1, x2: cx2, y2: cy2,
  597.                         x: (cx1 + cx2) / 2,
  598.                         y: (cy1 + cy2) / 2
  599.                     });
  600.                 }
  601.             }

  602.             if (candidates.length > 0) {
  603.                 var 发送按钮候选 = [];
  604.                 for (var ci = 0; ci < candidates.length; ci++) {
  605.                     var cand = candidates[ci];
  606.                     if (cand.y1 >= 输入框信息.y1 + 300) {
  607.                         发送按钮候选.push(cand);
  608.                     }
  609.                 }
  610.                
  611.                 if (发送按钮候选.length > 0) {
  612.                     发送按钮候选.sort(function(a, b) {
  613.                         return b.x1 - a.x1;
  614.                     });
  615.                     var 选中 = 发送按钮候选[0];
  616.                     print.log("✓ 发送按钮定位:输入框右侧下方clickable元素,坐标(" + Math.round(选中.x) + "," + Math.round(选中.y) + ")");
  617.                     return { x: 选中.x, y: 选中.y };
  618.                 }
  619.                
  620.                 candidates.sort(function(a, b) {
  621.                     return b.x1 - a.x1;
  622.                 });
  623.                 var 选中 = candidates[0];
  624.                 print.log("✓ 发送按钮定位:输入框右侧clickable元素,坐标(" + Math.round(选中.x) + "," + Math.round(选中.y) + ")");
  625.                 return { x: 选中.x, y: 选中.y };
  626.             }

  627.             var 预估X = 输入框信息.x2 + 100;
  628.             var 预估Y = 输入框信息.centerY;
  629.             print.log("⚠ 发送按钮使用输入框右侧兜底坐标(" + Math.round(预估X) + "," + Math.round(预估Y) + ")");
  630.             return { x: 预估X, y: 预估Y };
  631.         }
  632.     }

  633.     print.log("⚠ 发送按钮使用屏幕右侧兜底策略");
  634.     return {
  635.         x: 屏幕宽 * 0.92,
  636.         y: 屏幕高 * 0.92
  637.     };
  638. }

  639. function 等待AI回答完成(发送前的最后文本, 发送前回答数量) {
  640.     var 已耗时 = 0;
  641.     var 检查间隔秒 = 1;

  642.     print.log("发送前最后AI回答:'" + 发送前的最后文本 + "',发送前回答数量:" + 发送前回答数量);

  643.     while (已耗时 < 等待回答超时秒) {
  644.         sleep.second(秒 = 检查间隔秒);
  645.         已耗时 += 检查间隔秒;

  646.         xml = 获取UI();
  647.         var 回答列表 = 采集AI回答列表(xml);
  648.         
  649.         if (回答列表.length > 0) {
  650.             var 当前最后回答 = 回答列表[回答列表.length - 1];
  651.             
  652.             var 有新回答 = (当前最后回答 !== 发送前的最后文本);
  653.             var 回答数量增加 = (回答列表.length > 发送前回答数量);
  654.             
  655.             if (有新回答 || 回答数量增加) {
  656.                 print.log("✓ 检测到新回答(" + 已耗时 + "秒):'" + 当前最后回答 + "',数量:" + 回答列表.length);
  657.                
  658.                 var 等待完成 = 0;
  659.                 var 上次长度 = 字符串长度(当前最后回答);
  660.                 while (等待完成 < 回答输出等待秒) {
  661.                     sleep.second(秒 = 1);
  662.                     等待完成++;
  663.                     
  664.                     xml = 获取UI();
  665.                     var 当前列表 = 采集AI回答列表(xml);
  666.                     if (当前列表.length > 0) {
  667.                         var 当前文本 = 当前列表[当前列表.length - 1];
  668.                         if (字符串长度(当前文本) === 上次长度) {
  669.                             print.log("✓ 文本停止变化,返回采集结果:" + 当前文本);
  670.                             return 当前文本;
  671.                         }
  672.                         上次长度 = 字符串长度(当前文本);
  673.                     }
  674.                 }
  675.                
  676.                 var 最终列表 = 采集AI回答列表(xml);
  677.                 if (最终列表.length > 0) {
  678.                     var 最终文本 = 最终列表[最终列表.length - 1];
  679.                     print.log("✓ 采集成功,返回结果:" + 最终文本);
  680.                     return 最终文本;
  681.                 }
  682.             }
  683.         }
  684.     }

  685.     print.log("⚠ 等待AI回答超时(" + 等待回答超时秒 + "秒),尝试返回当前内容");
  686.     xml = 获取UI();
  687.     var 兜底列表 = 采集AI回答列表(xml);
  688.     if (兜底列表.length > 0) {
  689.         var 兜底文本 = 兜底列表[兜底列表.length - 1];
  690.         print.log("✓ 超时兜底:返回当前采集到的回答:" + 兜底文本);
  691.         return 兜底文本;
  692.     }
  693.     return null;
  694. }

  695. // ========== 主流程开始 ==========

  696. function 主流程() {
  697.     // 步骤1:全屏截图(B站验证码页面)
  698.     print.log("\n========== 步骤1:全屏截图B站验证码 ==========");
  699.     var 截图成功 = 全屏截图(截图保存路径);
  700.     if (!截图成功) {
  701.         print.log("✗ 截图失败,退出流程");
  702.         print.log("===== 元宝识别验证码拖动B站流程结束 =====");
  703.         return;
  704.     }

  705.     // 步骤2:启动元宝APP
  706.     print.log("\n========== 步骤2:启动元宝APP ==========");
  707.     try {
  708.         app.openApp(元宝包名);
  709.         print.log("✓ 已启动元宝");
  710.     } catch (e) {
  711.         print.log("⚠ 启动失败:" + e.message);
  712.     }
  713.     sleep.second(秒 = 5);

  714.     // 步骤3:确认进入对话页面
  715.     print.log("\n========== 步骤3:确认进入对话页面 ==========");
  716.     var xml = 获取UI();
  717.     var hasRecyclerView = (xml.indexOf("chat_recycler_view") !== -1);
  718.     if (!hasRecyclerView) {
  719.         print.log("⚠ 当前页面可能不是元宝对话页,再次等待");
  720.         sleep.second(秒 = 3);
  721.         xml = 获取UI();
  722.         hasRecyclerView = (xml.indexOf("chat_recycler_view") !== -1);
  723.     }

  724.     if (hasRecyclerView) {
  725.         print.log("✓ 已进入元宝对话页面");
  726.     } else {
  727.         print.log("⚠ 未检测到消息列表,继续尝试");
  728.     }

  729.     // 步骤4:记录发送前的最后一条AI回答和数量
  730.     var 发送前回答列表 = 采集AI回答列表(xml);
  731.     var 发送前回答数量 = 发送前回答列表.length;
  732.     var 发送前最后文本 = "";
  733.     if (发送前回答列表.length > 0) {
  734.         发送前最后文本 = 发送前回答列表[发送前回答列表.length - 1];
  735.     }
  736.     print.log("✓ 发送前回答数量:" + 发送前回答数量 + ",最后文本:'" + 发送前最后文本 + "'");

  737.     // 步骤5:点击加号按钮打开附件菜单
  738.     print.log("\n========== 步骤5:点击加号按钮打开附件菜单 ==========");
  739.     var 加号按钮 = 查找加号按钮(xml);
  740.     agent.click(加号按钮.x, 加号按钮.y);
  741.     print.log("✓ 已点击加号按钮,坐标(" + Math.round(加号按钮.x) + "," + Math.round(加号按钮.y) + ")");
  742.     sleep.second(秒 = 2);

  743.     // 步骤6:选择相册或图片
  744.     print.log("\n========== 步骤6:选择相册或图片 ==========");
  745.     var 相册选择成功 = false;
  746.     var 尝试次数 = 0;
  747.     while (!相册选择成功 && 尝试次数 < 5) {
  748.         尝试次数++;
  749.         xml = 获取UI();
  750.         
  751.         if (是否在系统相册页面(xml)) {
  752.             print.log("✓ 已进入系统相册页面");
  753.             相册选择成功 = true;
  754.             break;
  755.         }
  756.         
  757.         var 相册选项 = 查找相册选项(xml);
  758.         if (相册选项) {
  759.             agent.click(相册选项.x, 相册选项.y);
  760.             print.log("✓ 已点击相册选项,坐标(" + Math.round(相册选项.x) + "," + Math.round(相册选项.y) + ")");
  761.             sleep.second(秒 = 2);
  762.             相册选择成功 = true;
  763.             break;
  764.         }
  765.         
  766.         var imgCount = (xml.match(/class="android\.widget\.ImageView"/g) || []).length;
  767.         if (imgCount >= 4) {
  768.             print.log("✓ 加号菜单底部已显示图片列表(检测到" + imgCount + "个图片)");
  769.             相册选择成功 = true;
  770.             break;
  771.         }
  772.         
  773.         print.log("⚠ 第" + 尝试次数 + "次尝试:未找到相册选项,等待重试");
  774.         sleep.second(秒 = 1);
  775.     }

  776.     // 步骤7:选择第一张图片(处理系统相册和图片预览页面)
  777.     print.log("\n========== 步骤7:选择第一张图片 ==========");
  778.     var 图片选择成功 = false;
  779.     var 图片尝试次数 = 0;
  780.     while (!图片选择成功 && 图片尝试次数 < 10) {
  781.         图片尝试次数++;
  782.         xml = 获取UI();
  783.         
  784.         if (图片尝试次数 === 1) {
  785.             var pkgMatch = xml.match(/package="([^"]+)"/);
  786.             print.log("调试:当前包名=" + (pkgMatch ? pkgMatch[1] : "未知"));
  787.             print.log("调试:XML前300字符=" + xml.substring(0, 300));
  788.             print.log("调试:是否有edConversationInput=" + (xml.indexOf("edConversationInput") !== -1));
  789.             print.log("调试:是否有chat_recycler_view=" + (xml.indexOf("chat_recycler_view") !== -1));
  790.             var dbgImgCount = (xml.match(/class="android\.widget\.ImageView"/g) || []).length;
  791.             print.log("调试:ImageView数量=" + dbgImgCount);
  792.         }
  793.         
  794.         if (是否在图片预览页面(xml)) {
  795.             var 确认按钮 = 查找图片预览确认按钮(xml);
  796.             agent.click(确认按钮.x, 确认按钮.y);
  797.             print.log("✓ 已点击图片预览确认按钮,坐标(" + Math.round(确认按钮.x) + "," + Math.round(确认按钮.y) + ")");
  798.             图片选择成功 = true;
  799.             sleep.second(秒 = 3);
  800.             break;
  801.         }
  802.         
  803.         if (是否在系统相册页面(xml)) {
  804.             var 第一张图片 = 查找第一张图片(xml);
  805.             if (第一张图片) {
  806.                 agent.click(第一张图片.x, 第一张图片.y);
  807.                 print.log("✓ 已点击第一张图片右上角小圆点,坐标(" + Math.round(第一张图片.x) + "," + Math.round(第一张图片.y) + ")");
  808.                 sleep.second(秒 = 2);
  809.                
  810.                 xml = 获取UI();
  811.                 var 选择按钮 = 查找相册选择按钮(xml);
  812.                 if (选择按钮) {
  813.                     agent.click(选择按钮.x, 选择按钮.y);
  814.                     print.log("✓ 已点击选择按钮,坐标(" + Math.round(选择按钮.x) + "," + Math.round(选择按钮.y) + ")");
  815.                     图片选择成功 = true;
  816.                     sleep.second(秒 = 3);
  817.                     break;
  818.                 } else {
  819.                     print.log("⚠ 第" + 图片尝试次数 + "次:未找到选择按钮,重新获取XML重试");
  820.                     sleep.second(秒 = 1);
  821.                     continue;
  822.                 }
  823.             } else {
  824.                 print.log("⚠ 系统相册未找到图片");
  825.                 sleep.second(秒 = 1);
  826.                 continue;
  827.             }
  828.         }
  829.         
  830.         print.log("⚠ 第" + 图片尝试次数 + "次尝试:未检测到相册页面,等待重试");
  831.         sleep.second(秒 = 1);
  832.     }

  833.     // 步骤8:等待图片添加到输入区域(等待回到元宝对话页面)
  834.     print.log("\n========== 步骤8:等待图片添加到输入区域 ==========");
  835.     var 图片添加成功 = false;
  836.     var 等待尝试次数 = 0;
  837.     while (!图片添加成功 && 等待尝试次数 < 10) {
  838.         等待尝试次数++;
  839.         xml = 获取UI();
  840.         
  841.         var packageMatch = xml.match(/package="([^"]+)"/);
  842.         if (packageMatch && packageMatch[1] === 元宝包名) {
  843.             print.log("✓ 已回到元宝对话页面");
  844.             if (xml.indexOf("edConversationInput") !== -1) {
  845.                 print.log("✓ 图片已添加到输入区域");
  846.                 图片添加成功 = true;
  847.                 break;
  848.             }
  849.         }
  850.         
  851.         print.log("⚠ 第" + 等待尝试次数 + "次尝试:图片尚未添加,等待重试");
  852.         sleep.second(秒 = 1);
  853.     }
  854.    
  855.     if (!图片添加成功) {
  856.         print.log("⚠ 多次等待图片未添加,继续后续步骤");
  857.     }

  858.     // 步骤9:粘贴文字询问拖动距离
  859.     print.log("\n========== 步骤9:粘贴文字询问拖动距离 ==========");
  860.     xml = 获取UI();
  861.     var 输入框 = 查找输入框中心(xml);
  862.     var AI回答 = null;
  863.     if (输入框) {
  864.         agent.click(输入框.x, 输入框.y);
  865.         sleep.second(秒 = 1);
  866.         粘贴文本(提问话术);
  867.         print.log("✓ 已粘贴文本:" + 提问话术);
  868.         sleep.second(秒 = 2);

  869.         // 步骤10:发送图片和文字
  870.         print.log("\n========== 步骤10:发送图片和文字 ==========");
  871.         xml = 获取UI();
  872.         var 发送按钮 = 查找发送按钮中心(xml);
  873.         if (发送按钮) {
  874.             agent.click(发送按钮.x, 发送按钮.y);
  875.             print.log("✓ 已点击发送按钮,坐标(" + Math.round(发送按钮.x) + "," + Math.round(发送按钮.y) + ")");
  876.         } else {
  877.             agent.shell("input keyevent 66");
  878.             print.log("⚠ 未找到发送按钮,已尝试按回车发送");
  879.         }
  880.         sleep.second(秒 = 3);

  881.         // 步骤11:等待元宝AI回答
  882.         print.log("\n========== 步骤11:等待元宝AI回答 ==========");
  883.         AI回答 = 等待AI回答完成(发送前最后文本, 发送前回答数量);
  884.     } else {
  885.         print.log("⚠ 未找到输入框");
  886.     }
  887.    
  888.     if (!AI回答) {
  889.         print.log("✗ 未获取到AI回答");
  890.         print.log("===== 元宝识别验证码拖动B站流程结束 =====");
  891.         return;
  892.     }

  893.     print.log("\n✓ 采集到AI回答");
  894.     print.log("--- 采集内容开始 ---");
  895.     print.log(AI回答);
  896.     print.log("--- 采集内容结束 ---");

  897.     // 步骤12:解析拖动距离坐标
  898.     print.log("\n========== 步骤12:解析拖动距离坐标 ==========");
  899.     print.log("✓ AI原始回答:'" + AI回答 + "'");
  900.    
  901.     var 所有数字 = AI回答.match(/\d+/g);
  902.     var 拖动距离像素 = null;
  903.     var AI图像宽度 = null;
  904.    
  905.     if (所有数字 && 所有数字.length >= 2) {
  906.         var 数字列表 = [];
  907.         for (var i = 0; i < 所有数字.length; i++) {
  908.             数字列表.push(parseInt(所有数字[i]));
  909.         }
  910.         print.log("✓ 提取到所有数字:" + 数字列表.join(", "));
  911.         
  912.         if (数字列表.length >= 5) {
  913.             var x1 = 数字列表[0];
  914.             var y1 = 数字列表[1];
  915.             var x2 = 数字列表[2];
  916.             var y2 = 数字列表[3];
  917.             AI图像宽度 = 数字列表[4];
  918.             拖动距离像素 = Math.abs(x2 - x1);
  919.             print.log("✓ 识别到两组坐标+图像宽度:(" + x1 + "," + y1 + ") 和 (" + x2 + "," + y2 + "),图像宽度=" + AI图像宽度);
  920.             print.log("✓ 计算拖动距离:|x2 - x1| = |" + x2 + " - " + x1 + "| = " + 拖动距离像素);
  921.         } else if (数字列表.length >= 4) {
  922.             var x1 = 数字列表[0];
  923.             var y1 = 数字列表[1];
  924.             var x2 = 数字列表[2];
  925.             var y2 = 数字列表[3];
  926.             拖动距离像素 = Math.abs(x2 - x1);
  927.             AI图像宽度 = Math.max(x1, x2) + 100;
  928.             print.log("✓ 识别到两组坐标格式:(" + x1 + "," + y1 + ") 和 (" + x2 + "," + y2 + ")");
  929.             print.log("✓ 计算拖动距离:|x2 - x1| = |" + x2 + " - " + x1 + "| = " + 拖动距离像素);
  930.             print.log("✓ 估算图像宽度:max(x1,x2)+100 = " + AI图像宽度);
  931.         } else if (数字列表.length >= 2) {
  932.             var 坐标匹配 = AI回答.match(/(\d+)\s*[,,]\s*(\d+)/);
  933.             if (坐标匹配) {
  934.                 var cx1 = parseInt(坐标匹配[1]);
  935.                 var cx2 = parseInt(坐标匹配[2]);
  936.                 拖动距离像素 = Math.abs(cx2 - cx1);
  937.                 AI图像宽度 = Math.max(cx1, cx2) + 100;
  938.                 print.log("✓ 识别到坐标格式:(" + cx1 + "," + cx2 + "),计算距离:" + 拖动距离像素);
  939.             } else {
  940.                 拖动距离像素 = 数字列表[0];
  941.                 print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
  942.             }
  943.         } else {
  944.             拖动距离像素 = 数字列表[0];
  945.             print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
  946.         }
  947.     } else if (所有数字 && 所有数字.length === 1) {
  948.         拖动距离像素 = parseInt(所有数字[0]);
  949.         print.log("✓ 提取到单个数字(拖动距离):" + 拖动距离像素);
  950.     } else {
  951.         print.log("✗ 未找到有效的拖动距离");
  952.         print.log("===== 元宝识别验证码拖动B站流程结束 =====");
  953.         return;
  954.     }
  955.    
  956.     var 图像缩放系数 = 1.0;
  957.     if (AI图像宽度 && AI图像宽度 > 0 && AI图像宽度 < 屏幕宽) {
  958.         图像缩放系数 = 屏幕宽 / AI图像宽度;
  959.         if (图像缩放系数 > 5) {
  960.             图像缩放系数 = 1.0;
  961.         } else {
  962.             拖动距离像素 = Math.round(拖动距离像素 * 图像缩放系数);
  963.             print.log("✓ 图像缩放补偿:AI图像宽度=" + AI图像宽度 + ",屏幕宽=" + 屏幕宽);
  964.             print.log("✓ 缩放系数=" + 图像缩放系数.toFixed(2) + ",补偿后拖动距离=" + 拖动距离像素);
  965.         }
  966.     } else if (拖动距离像素 < 200) {
  967.         图像缩放系数 = 屏幕宽 / 750;
  968.         拖动距离像素 = Math.round(拖动距离像素 * 图像缩放系数);
  969.         print.log("✓ 单数字模式补偿:假设AI图像宽度≈750,缩放系数=" + 图像缩放系数.toFixed(2));
  970.         print.log("✓ 补偿后拖动距离=" + 拖动距离像素);
  971.     }
  972.    
  973.     验证码滑块距离 = {
  974.         x: 拖动距离像素,
  975.         y: 0
  976.     };

  977.     // 步骤13:切换回B站并拖动滑块
  978.     print.log("\n========== 步骤13:切换回B站并拖动滑块 ==========");
  979.    
  980.     agent.shell("input keyevent 187");
  981.     print.log("✓ 已按后台键打开任务列表");
  982.     sleep.second(秒 = 2);
  983.    
  984.     xml = 获取UI();
  985.     var biliIdx = xml.indexOf('哔哩哔哩');
  986.     if (biliIdx === -1) {
  987.         biliIdx = xml.indexOf('bilibili');
  988.     }
  989.     if (biliIdx === -1) {
  990.         biliIdx = xml.indexOf('B站');
  991.     }
  992.    
  993.     if (biliIdx !== -1) {
  994.         var 段 = xml.substring(biliIdx);
  995.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  996.         if (m) {
  997.             var clickX = (parseInt(m[1]) + parseInt(m[3])) / 2;
  998.             var clickY = (parseInt(m[2]) + parseInt(m[4])) / 2;
  999.             agent.click(clickX, clickY);
  1000.             print.log("✓ 已点击B站任务卡片,坐标(" + Math.round(clickX) + "," + Math.round(clickY) + ")");
  1001.         }
  1002.     } else {
  1003.         print.log("⚠ 未找到B站任务卡片,尝试直接打开");
  1004.         try {
  1005.             app.openApp(B站包名);
  1006.             print.log("✓ 已打开B站");
  1007.         } catch (e) {
  1008.             print.log("⚠ 打开B站失败:" + e.message);
  1009.         }
  1010.     }
  1011.     sleep.second(秒 = 3);

  1012.     xml = 获取UI();
  1013.     var 验证码区域左边界 = 屏幕宽 * 0.15;
  1014.    
  1015.     var 滑块轨道匹配 = xml.match(/<node[^>]*?text="拖动滑块完成拼图"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  1016.     if (滑块轨道匹配) {
  1017.         验证码区域左边界 = parseInt(滑块轨道匹配[1]);
  1018.     }

  1019.     var 拖动距离 = 验证码滑块距离.x * 滑块校准系数;

  1020.     var startX = 验证码区域左边界 + 50;
  1021.     var startY = 屏幕高 * 0.42;
  1022.     var endX = startX + 拖动距离;
  1023.     var endY = startY;

  1024.     print.log("✓ 验证码区域左边界: " + 验证码区域左边界 + ", 拖动距离: " + 拖动距离);
  1025.     agent.swip(startX, startY, endX, endY, 2000);
  1026.     print.log("✓ 已拖动滑块,起点(" + Math.round(startX) + "," + Math.round(startY) + "),终点(" + Math.round(endX) + "," + Math.round(endY) + ")");
  1027. }

  1028. 主流程();

  1029. print.log("\n===== 元宝识别验证码拖动B站流程结束 =====");
复制代码



unto示例千问自动采集文章保存记事本nextnocontent
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

相关导读了
    采集亚马逊正版群发工具有没有?
    Apr.20旅行X心语今天来说说YYPOST新功能的一个灵活用法,采集亚马逊商品信息,并且获得排名的软件,亚马逊现在越来越多客户做,淘宝的水是越来越清了,以前做电商的客户,现在都转战到外国,最赚钱的要数一些客户往亚马逊里堆了吧,拿我这个YYPOST的客户,最多的是采集,分析排名,刷价格,刷数量,改价,刷访问量等等技术

    企业发展B2B网站有什么东东软件可以发呢
    标题企业发展网B2B软件,现在虽然B2B网站收录不错,可愁的是心急的人们,他们太想一口吃撑胖子了,发帖宣传虽然不能像佛系那样淡定,但也不能像跑火车那般急躁对待,自己内容不收录,完全是自己操作内容问题,可以参考一下别人的内容是怎么弄的,然后自己要试着转变,而且收录这个内容,常常会变化的,不是一种规则就吃到老

    搜房天下房聊软件哪一个好呢
    本帖最后由 发帖软件 于 2019-5-22 16:15 编辑 2搜房天下群发房聊信息软件,开始本来打算做58同城的,但发一个就要一次点触验证码,这就让人没有感觉到存在的价值了吧,都是卖二手房和新房的搜房天下倒是可以发即时聊天信息,也没有发现他这个网站有啥子限制,登陆一个搜房天下账号,然后采集回来分类列表的网址,然后就一

    大家坛有没有好用的群发工具下载呢
    当你的笑容给我礼貌的招呼,大家坛全自动发帖软件,宣传推广是一场持久战,总是有一些人把软件用了一天,或是几个小时,就觉得自己付出太多了,那加进来的粉丝,或是流量,应该是和宣传多少成正比的,其实没有这么便宜的事,就像很多阅读量超过一百万的视频,或是电影,真正会在屏幕打赏的人不会超过三千,真正大额打赏给主

    群发正版软件中国塑料网
    中国塑料网群发软件YYPOST脚本下载地址,这个网站会有一个很奇怪的问题就是你在首页登陆无半个验证码,但在登陆网址登陆就会有一个验证码,所以我们灵活一些,在首页登陆就不用输入验证码了哈。网站秒收录比较高,但发的都是五金和建筑行业,先前有很多人都是发土建工程的大公司操作的,现在这个网站专为那个行业诞生的吧。

    OpenStreetMap网站正版2019年发帖工具下载
    本帖最后由 发帖软件 于 2019-5-21 11:13 编辑 OpenStreetMap网站全自动群发,OpenStreetMapOpenStreetMap(简称OSM,中文是公开地图)是一个网上地图协作计划,目标是创造一个内容自由且能让所有人编辑的世界地图。有的人编辑地图然后等收录,有的人发日志等收录,我们这里也是利用地图日志做为宣传的目标,简单的脚本理

    搜房天下全自动收短信全自动识别验证码注册账号软件
    房天下自动注册机,这个脚本是前几天发房聊的脚本廷伸品种,这个脚本能做到自动注册账号,自动保存账号,自动发房聊的效果,不过今天我们主要说一说怎么注册账号写脚本吧,这个搜房天天下的账号,可以发提问,可以发房聊,发论坛,发博客,还有发个人中心页都是有秒收的效果的,这样就省去了去买号,去乱花钱的效果了吧,而

    企业邮箱安卓端有什么APP软件可以发的呢
    请输入标题企业邮箱安卓发发送邮箱脚本,这个脚本是利用企业邮箱进行群发的,全程是一种模拟手工操作的过程,所以封号是很少的,而且企业邮箱群发到普通QQ邮箱不容易进垃圾箱中的,所以这个脚本也是这样的原理,不过最好是利用一些多开器,登陆多点的QQ邮箱账号会比较流畅一些,然后用软件一个一个的切换APP进行群发邮件会

    头条留评论软件有没有好用的呢?
    今天整一个今日头条留言软件,对于留言YYPOST是优势是比较大的存在,因为他往往专注一些下拉定位的优点,像今日头条这样,还是需要一些特殊下拉定位的,因为他新闻有长有短,有图有视频的,所以综合起来定位是比较难的,如果用POST也不是很轻松可以破解他的加密参数。这个脚本也是有一个不好的地方就是换号会比较麻烦,您电

    单网页生成神器
    最近新技术,网页生成机占领了整个网络的半壁江山,效果很疯狂,虽然不知道能持续多久,作为开发软件的领头者,一直在找收录的方法,一直在努力创新着,一直被人模仿,却从没有被超越过,这个网页生成机,已经出来有一段时间了,一直没有拿出来分享,醉过醉过,它是利用的一些小小收录漏洞整的,您最好用一些老站域名,进行

关闭
快速回复 返回列表 返回顶部
本站自动发贴软件,是现在最流行的做脚本软件,这种发贴工具,不但发贴收录快,而且抢占好的先机,完全自由编辑,实现针对性群发模拟操作,软件可以顶贴,也可以发贴,可以兼容支持Discuz、PHPWind、Dvbbs三大主流论坛,有手机验证码收件,邮件收发的功能,支持验证码识别,注册问题识别,多线程任务,自动上传头像,自动激活注册邮件,兼容防注册插件,本站软件原创正版,更新效率最快的原创软件。 『网络推广软件』『自动发帖软件』『 自动发帖