信息发布软件,b2b软件,广告发布软件

 找回密码
 立即注册
搜索
查看: 3|回复: 0
打印 上一主题 下一主题

[宣传软件网站动态] 示例千问自动采集文章保存记事本

[复制链接]

790

主题

874

帖子

5602

积分

积分
5602

资讯缩略图:

资讯发布日期:2026-07-15

资讯发布简介:示例千问自动采集文章保存记事本

资讯关键词:示例千问自动采集文章保存记事本

资讯所属分类:IT资讯 SEO资讯 

联系:

① 本信息收集于网络,如有不对的地方欢迎联系我纠正!
② 本信息免费收录,不存在价格的问题!
③ 如果您的网站也想这样出现在这里,请您加好友情链接,我当天会审核通过!

④友情链接关键字:软件网站分类目录 网址:http://www.postbbs.com/

资讯详细描述
示例千问自动采集文章保存记事本
示例千问自动采集文章保存记事本 b2b软件

  1. // AIWROK 自动化流程:启动千问 → 输入问题 → 点击发送 → 等待AI回答 → 采集回答内容 → 保存到文件
  2. // 全程使用 agent.getXml() 获取界面源码
  3. // 包名:com.aliyun.tongyi(千问)

  4. print.log("===== 千问对话采集流程启动 =====");
  5. print.time();

  6. // ========== 配置区 ==========
  7. var 千问包名 = "com.aliyun.tongyi";

  8. // 输出文件路径(JSON格式,UTF-8编码)
  9. var 输出文件路径 = "/sdcard/千问对话记录.txt";

  10. // 要发送的问题列表(按顺序发送)
  11. var 要发送的问题列表 = [
  12.     "你好,请用一句话介绍你自己",
  13.     "中国平安股票最近走势如何?",
  14.     "招商银行持有3年卖出需要交股息税吗?"
  15. ];

  16. // 发送后等待AI回答的最大秒数(整体超时,最长35秒)
  17. var 等待回答超时秒 = 35;

  18. // 检测到新回答出现后,再等待多少秒让回答尽量输出完整(然后直接返回)
  19. var 回答输出等待秒 = 12;

  20. // 每个问题之间的间隔秒数
  21. var 问题间隔秒 = 2;

  22. // ========== 获取设备信息 ==========
  23. var 屏幕宽 = screen.getScreenWidth();
  24. var 屏幕高 = screen.getScreenHeight();
  25. print.log("屏幕尺寸:" + 屏幕宽 + " x " + 屏幕高);
  26. print.log("代理状态:" + (agent.isOpen() ? "已开启" : "未开启"));

  27. // ========== 工具函数 ==========

  28. // 获取 UI XML 字符串(使用 agent.getXml(),强制转为字符串)
  29. function 获取UI() {
  30.     var xml = agent.getXml();
  31.     // agent.getXml() 返回对象,需强制转为字符串
  32.     return "" + xml;
  33. }

  34. // 字符串长度兼容函数(避免 Java String 对象 .length() 方法问题)
  35. function 字符串长度(s) {
  36.     var str = "" + s;
  37.     return str.length;
  38. }

  39. // HTML实体解码(千问TextView中的换行符等会被编码为
  40. ' 等)
  41. function 解码HTML实体(s) {
  42.     var str = "" + s;
  43.     str = str.replace(/
  44. /g, "\n");
  45.     str = str.replace(/
  46. /g, "\r");
  47.     str = str.replace(/        /g, "\t");
  48.     str = str.replace(/'/g, "'");
  49.     str = str.replace(/"/g, '"');
  50.     str = str.replace(/"/g, '"');
  51.     str = str.replace(/'/g, "'");
  52.     str = str.replace(/&/g, "&");
  53.     str = str.replace(/</g, "<");
  54.     str = str.replace(/>/g, ">");
  55.     return str;
  56. }

  57. // 采集千问 RecyclerView 中所有长文本 TextView(即AI回答)
  58. // 参数 严格过滤: true=排除短文本按钮等, false=不过滤(用于检测新回答出现,更灵敏)
  59. function 采集AI回答列表(xml, 严格过滤) {
  60.     if (严格过滤 === undefined) 严格过滤 = true;
  61.     var xmlStr = "" + xml;
  62.     var 回答列表 = [];

  63.     // 定位 RecyclerView 节点(千问消息列表使用 RecyclerView)
  64.     var rvPattern = /<node[^>]*?class="androidx\.recyclerview\.widget\.RecyclerView"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  65.     var rvMatch;
  66.     var 消息列表区域 = null;

  67.     while ((rvMatch = rvPattern.exec(xmlStr)) !== null) {
  68.         var rx1 = parseInt(rvMatch[1]);
  69.         var ry1 = parseInt(rvMatch[2]);
  70.         var rx2 = parseInt(rvMatch[3]);
  71.         var ry2 = parseInt(rvMatch[4]);
  72.         var 高度 = ry2 - ry1;
  73.         var 宽度 = rx2 - rx1;

  74.         if (高度 > 500 && 宽度 > 屏幕宽 * 0.8) {
  75.             消息列表区域 = {x1: rx1, y1: ry1, x2: rx2, y2: ry2};
  76.             break;
  77.         }
  78.     }

  79.     if (!消息列表区域) {
  80.         print.log("⚠ 未找到消息列表RecyclerView节点");
  81.         return 回答列表;
  82.     }

  83.     print.log("✓ 找到消息列表区域:[" + 消息列表区域.x1 + "," + 消息列表区域.y1 + "][" + 消息列表区域.x2 + "," + 消息列表区域.y2 + "]");

  84.     // 提取消息列表区域内的所有 TextView(两阶段匹配:先找节点,再提取属性)
  85.     var tvPattern = /<node[^>]*?class="android\.widget\.TextView"[^>]*?\/?>/g;
  86.     var tvMatch;

  87.     while ((tvMatch = tvPattern.exec(xmlStr)) !== null) {
  88.         var tvNode = tvMatch[0];

  89.         // 从节点中提取文本(支持双引号和单引号)
  90.         var textMatch = tvNode.match(/text="([^"]+)"/);
  91.         if (!textMatch) {
  92.             textMatch = tvNode.match(/text='([^']+)'/);
  93.         }
  94.         if (!textMatch) continue;
  95.         var 文本 = textMatch[1];

  96.         // 从节点中提取边界
  97.         var boundsMatch = tvNode.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  98.         if (!boundsMatch) continue;
  99.         var tx1 = parseInt(boundsMatch[1]);
  100.         var ty1 = parseInt(boundsMatch[2]);
  101.         var tx2 = parseInt(boundsMatch[3]);
  102.         var ty2 = parseInt(boundsMatch[4]);

  103.         // 判断该 TextView 是否在消息列表区域内
  104.         var 在区域内 = (tx1 >= 消息列表区域.x1 && tx2 <= 消息列表区域.x2 &&
  105.                         ty1 >= 消息列表区域.y1 && ty2 <= 消息列表区域.y2);

  106.         if (!在区域内) continue;

  107.         var 解码文本 = 解码HTML实体(文本);

  108.         // 排除用户消息特征:位于消息列表顶部区域(y坐标较小)且是单行短文本
  109.         var 是用户消息 = (ty1 < 消息列表区域.y1 + 500) && (解码文本.indexOf("\n") === -1) && (字符串长度(解码文本) < 100);
  110.         
  111.         // 排除搜索步骤文本(包含"查询"、"检索"、"调研"等关键词的是搜索计划,不是最终回答)
  112.         var 是搜索步骤 = (解码文本.indexOf("查询") !== -1 || 解码文本.indexOf("检索") !== -1 ||
  113.                           解码文本.indexOf("调研") !== -1 || 解码文本.indexOf("确认") !== -1 ||
  114.                           解码文本.indexOf("分析") !== -1 || 解码文本.indexOf("查找") !== -1) &&
  115.                          (字符串长度(解码文本) < 500);
  116.         
  117.         // 排除视频推荐区域的文本(视频推荐通常在AI回答下方,y坐标较大且有特定特征)
  118.         // AI回答通常在消息列表顶部区域,视频推荐在下方
  119.         var 消息列表高度 = 消息列表区域.y2 - 消息列表区域.y1;
  120.         var 是视频推荐 = (ty1 > 消息列表区域.y1 + 消息列表高度 * 0.3) &&
  121.                          (解码文本.indexOf("笔记") !== -1 || 解码文本.indexOf("作者") !== -1 ||
  122.                           字符串长度(解码文本) < 30);
  123.         
  124.         if (严格过滤) {
  125.             if (!是用户消息 && !是搜索步骤 && !是视频推荐 && (解码文本.indexOf("\n") !== -1 || 字符串长度(解码文本) > 50)) {
  126.                 回答列表.push(解码文本);
  127.             }
  128.         } else {
  129.             if (!是用户消息 && !是搜索步骤 && !是视频推荐 && 字符串长度(解码文本) > 0) {
  130.                 回答列表.push(解码文本);
  131.             }
  132.         }
  133.     }

  134.     return 回答列表;
  135. }

  136. // 查找输入框中心坐标(查找 hint 文本为"发消息或按住说话..."的 TextView)
  137. function 查找输入框中心(xml) {
  138.     var xmlStr = "" + xml;

  139.     var inputIdx = xmlStr.indexOf('text="发消息或按住说话..."');
  140.     if (inputIdx === -1) {
  141.         inputIdx = xmlStr.indexOf("text='发消息或按住说话...'");
  142.     }
  143.     if (inputIdx !== -1) {
  144.         var 段 = xmlStr.substring(inputIdx);
  145.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  146.         if (m) {
  147.             print.log("✓ 输入框定位:hint文本匹配");
  148.             return {
  149.                 x: (parseInt(m[1]) + parseInt(m[3])) / 2,
  150.                 y: (parseInt(m[2]) + parseInt(m[4])) / 2
  151.             };
  152.         }
  153.     }

  154.     var editTextPattern = /<node[^>]*?class="android\.widget\.EditText"[^>]*?\/?>/g;
  155.     var etMatch;
  156.     while ((etMatch = editTextPattern.exec(xmlStr)) !== null) {
  157.         var etNode = etMatch[0];
  158.         var boundsMatch = etNode.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  159.         if (boundsMatch) {
  160.             var ex1 = parseInt(boundsMatch[1]);
  161.             var ey1 = parseInt(boundsMatch[2]);
  162.             var ex2 = parseInt(boundsMatch[3]);
  163.             var ey2 = parseInt(boundsMatch[4]);
  164.             
  165.             if (ey1 > 屏幕高 * 0.8) {
  166.                 print.log("✓ 输入框定位:EditText匹配");
  167.                 return {
  168.                     x: (ex1 + ex2) / 2,
  169.                     y: (ey1 + ey2) / 2
  170.                 };
  171.             }
  172.         }
  173.     }

  174.     var viewGroupPattern = /<node[^>]*?class="android\.view\.ViewGroup"[^>]*?clickable="true"[^>]*?\/?>/g;
  175.     var vgMatch;
  176.     while ((vgMatch = viewGroupPattern.exec(xmlStr)) !== null) {
  177.         var vgNode = vgMatch[0];
  178.         var boundsMatch = vgNode.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  179.         if (boundsMatch) {
  180.             var vx1 = parseInt(boundsMatch[1]);
  181.             var vy1 = parseInt(boundsMatch[2]);
  182.             var vx2 = parseInt(boundsMatch[3]);
  183.             var vy2 = parseInt(boundsMatch[4]);
  184.             
  185.             var vWidth = vx2 - vx1;
  186.             var vHeight = vy2 - vy1;
  187.             
  188.             if (vy1 > 屏幕高 * 0.8 && vWidth > 屏幕宽 * 0.4 && vWidth < 屏幕宽 * 0.8) {
  189.                 print.log("✓ 输入框定位:ViewGroup匹配");
  190.                 return {
  191.                     x: (vx1 + vx2) / 2,
  192.                     y: (vy1 + vy2) / 2
  193.                 };
  194.             }
  195.         }
  196.     }

  197.     print.log("⚠ 未找到输入框,使用兜底坐标");
  198.     return {
  199.         x: 屏幕宽 * 0.4,
  200.         y: 屏幕高 * 0.92
  201.     };
  202. }

  203. // 查找发送按钮坐标
  204. // 千问输入框下方右侧的按钮,输入文字后会变成发送按钮
  205. function 查找发送按钮中心(xml) {
  206.     var xmlStr = "" + xml;

  207.     // 1. 优先查找文字"发送"
  208.     var sendTextIdx = xmlStr.indexOf('text="发送"');
  209.     if (sendTextIdx === -1) {
  210.         sendTextIdx = xmlStr.indexOf("text='发送'");
  211.     }
  212.     if (sendTextIdx !== -1) {
  213.         var 段 = xmlStr.substring(sendTextIdx);
  214.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  215.         if (m) {
  216.             print.log("✓ 发送按钮定位:文本匹配");
  217.             return {
  218.                 x: (parseInt(m[1]) + parseInt(m[3])) / 2,
  219.                 y: (parseInt(m[2]) + parseInt(m[4])) / 2
  220.             };
  221.         }
  222.     }

  223.     // 2. 查找屏幕底部区域的点击区域(FrameLayout)
  224.     var clickablePattern = /<node[^>]*?clickable="true"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"[^>]*?\/?>/g;
  225.     var clickMatch;
  226.     var candidates = [];

  227.     while ((clickMatch = clickablePattern.exec(xmlStr)) !== null) {
  228.         var cx1 = parseInt(clickMatch[1]);
  229.         var cy1 = parseInt(clickMatch[2]);
  230.         var cx2 = parseInt(clickMatch[3]);
  231.         var cy2 = parseInt(clickMatch[4]);

  232.         if (cy1 > 屏幕高 * 0.85) {
  233.             candidates.push({
  234.                 x1: cx1, y1: cy1, x2: cx2, y2: cy2,
  235.                 x: (cx1 + cx2) / 2,
  236.                 y: (cy1 + cy2) / 2
  237.             });
  238.         }
  239.     }

  240.     if (candidates.length > 0) {
  241.         candidates.sort(function(a, b) {
  242.             return b.x1 - a.x1;
  243.         });
  244.         print.log("✓ 找到" + candidates.length + "个候选按钮,选择最右侧的,坐标(" + Math.round(candidates[0].x) + "," + Math.round(candidates[0].y) + ")");
  245.         return {
  246.             x: candidates[0].x,
  247.             y: candidates[0].y
  248.         };
  249.     }

  250.     // 3. 查找屏幕底部区域的 FrameLayout(千问发送按钮特征)
  251.     var flPattern = /<node[^>]*?class="android\.widget\.FrameLayout"[^>]*?\/?>/g;
  252.     var flMatch;
  253.     var flCandidates = [];

  254.     while ((flMatch = flPattern.exec(xmlStr)) !== null) {
  255.         var flNode = flMatch[0];
  256.         
  257.         if (flNode.indexOf('clickable="true"') === -1) continue;
  258.         
  259.         var boundsMatch = flNode.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  260.         if (!boundsMatch) continue;
  261.         
  262.         var fx1 = parseInt(boundsMatch[1]);
  263.         var fy1 = parseInt(boundsMatch[2]);
  264.         var fx2 = parseInt(boundsMatch[3]);
  265.         var fy2 = parseInt(boundsMatch[4]);

  266.         if (fy1 > 屏幕高 * 0.85) {
  267.             flCandidates.push({
  268.                 x1: fx1, y1: fy1, x2: fx2, y2: fy2,
  269.                 x: (fx1 + fx2) / 2,
  270.                 y: (fy1 + fy2) / 2
  271.             });
  272.         }
  273.     }

  274.     if (flCandidates.length > 0) {
  275.         flCandidates.sort(function(a, b) {
  276.             return b.x1 - a.x1;
  277.         });
  278.         print.log("✓ 找到" + flCandidates.length + "个FrameLayout候选,选择最右侧的,坐标(" + Math.round(flCandidates[0].x) + "," + Math.round(flCandidates[0].y) + ")");
  279.         return {
  280.             x: flCandidates[0].x,
  281.             y: flCandidates[0].y
  282.         };
  283.     }

  284.     // 4. 兜底:基于屏幕百分比定位发送按钮(输入框下方右侧)
  285.     print.log("⚠ 使用兜底策略定位发送按钮,坐标(" + Math.round(屏幕宽 * 0.92) + "," + Math.round(屏幕高 * 0.92) + ")");
  286.     return {
  287.         x: 屏幕宽 * 0.92,
  288.         y: 屏幕高 * 0.92
  289.     };
  290. }

  291. // 粘贴文本到当前焦点输入框(剪贴板法,兼容中文)
  292. function 粘贴文本(文本) {
  293.     try {
  294.         Clipboard.copy("" + 文本);
  295.     } catch (e) {
  296.         print.log("⚠ Clipboard.copy 失败:" + e.message);
  297.     }
  298.     sleep.millisecond(毫秒 = 300);

  299.     // 双保险:通过 shell 写剪贴板
  300.     try {
  301.         agent.shell("service call clipboard 3 i32 1 s16 '" + 文本 + "' i32 0");
  302.     } catch (e2) {
  303.         // 忽略错误
  304.     }
  305.     sleep.millisecond(毫秒 = 300);

  306.     // 触发粘贴:KEYCODE_PASTE = 279
  307.     agent.shell("input keyevent 279");
  308.     sleep.second(秒 = 1);
  309.     print.log("✓ 已粘贴文本:" + 文本);
  310. }

  311. // 查找并点击AI回答底部的展开按钮(向下箭头)
  312. // 千问长回答会折叠显示,需要点击底部向下箭头才能看到完整内容
  313. function 查找并点击展开按钮(xml) {
  314.     var xmlStr = "" + xml;
  315.    
  316.     // 1. 查找消息列表底部中间的小区域clickable节点(向下箭头特征)
  317.     var rvPattern = /<node[^>]*?class="androidx\.recyclerview\.widget\.RecyclerView"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  318.     var rvMatch;
  319.     while ((rvMatch = rvPattern.exec(xmlStr)) !== null) {
  320.         var rx1 = parseInt(rvMatch[1]);
  321.         var ry1 = parseInt(rvMatch[2]);
  322.         var rx2 = parseInt(rvMatch[3]);
  323.         var ry2 = parseInt(rvMatch[4]);
  324.         var 高度 = ry2 - ry1;
  325.         if (高度 > 500) {
  326.             var viewPattern = /<node[^>]*?clickable="true"[^>]*?\/?>/g;
  327.             var viewMatch;
  328.             while ((viewMatch = viewPattern.exec(xmlStr)) !== null) {
  329.                 var vNode = viewMatch[0];
  330.                 var boundsMatch = vNode.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  331.                 if (!boundsMatch) continue;
  332.                
  333.                 var vx1 = parseInt(boundsMatch[1]);
  334.                 var vy1 = parseInt(boundsMatch[2]);
  335.                 var vx2 = parseInt(boundsMatch[3]);
  336.                 var vy2 = parseInt(boundsMatch[4]);
  337.                
  338.                 var vWidth = vx2 - vx1;
  339.                 var vHeight = vy2 - vy1;
  340.                
  341.                 var 在区域内 = (vx1 >= rx1 && vx2 <= rx2 && vy1 >= ry1 && vy2 <= ry2);
  342.                 var 是小按钮 = (vWidth < 200 && vHeight < 200);
  343.                 var 在底部 = (vy1 > ry1 + 高度 * 0.7);
  344.                
  345.                 if (在区域内 && 是小按钮 && 在底部) {
  346.                     var centerX = (vx1 + vx2) / 2;
  347.                     var centerY = (vy1 + vy2) / 2;
  348.                     agent.click(centerX, centerY);
  349.                     print.log("✓ 已点击展开箭头(消息列表底部小按钮),坐标(" + Math.round(centerX) + "," + Math.round(centerY) + ")");
  350.                     sleep.second(秒 = 2);
  351.                     return true;
  352.                 }
  353.             }
  354.             break;
  355.         }
  356.     }

  357.     // 2. 查找文本"查看全部"的按钮
  358.     var textExpandIdx = xmlStr.indexOf('text="查看全部"');
  359.     if (textExpandIdx === -1) {
  360.         textExpandIdx = xmlStr.indexOf("text='查看全部'");
  361.     }
  362.     if (textExpandIdx !== -1) {
  363.         var 段 = xmlStr.substring(textExpandIdx);
  364.         var m = 段.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  365.         if (m) {
  366.             var x = (parseInt(m[1]) + parseInt(m[3])) / 2;
  367.             var y = (parseInt(m[2]) + parseInt(m[4])) / 2;
  368.             agent.click(x, y);
  369.             print.log("✓ 已点击查看全部按钮,坐标(" + Math.round(x) + "," + Math.round(y) + ")");
  370.             sleep.second(秒 = 2);
  371.             return true;
  372.         }
  373.     }

  374.     // 3. 查找 content-desc 含"展开"或"更多"的按钮
  375.     var expandIdx = xmlStr.indexOf('content-desc="展开"');
  376.     if (expandIdx === -1) {
  377.         expandIdx = xmlStr.indexOf('content-desc="更多"');
  378.     }
  379.     if (expandIdx !== -1) {
  380.         var 段2 = xmlStr.substring(expandIdx);
  381.         var m2 = 段2.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  382.         if (m2) {
  383.             var x2 = (parseInt(m2[1]) + parseInt(m2[3])) / 2;
  384.             var y2 = (parseInt(m2[2]) + parseInt(m2[4])) / 2;
  385.             agent.click(x2, y2);
  386.             print.log("✓ 已点击展开按钮(content-desc),坐标(" + Math.round(x2) + "," + Math.round(y2) + ")");
  387.             sleep.second(秒 = 1);
  388.             return true;
  389.         }
  390.     }

  391.     // 4. 查找文本"展开"或"更多"的按钮
  392.     var textExpandIdx2 = xmlStr.indexOf('text="展开"');
  393.     if (textExpandIdx2 === -1) {
  394.         textExpandIdx2 = xmlStr.indexOf('text="更多"');
  395.     }
  396.     if (textExpandIdx2 !== -1) {
  397.         var 段3 = xmlStr.substring(textExpandIdx2);
  398.         var m3 = 段3.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  399.         if (m3) {
  400.             var x3 = (parseInt(m3[1]) + parseInt(m3[3])) / 2;
  401.             var y3 = (parseInt(m3[2]) + parseInt(m3[4])) / 2;
  402.             agent.click(x3, y3);
  403.             print.log("✓ 已点击展开按钮(文本匹配),坐标(" + Math.round(x3) + "," + Math.round(y3) + ")");
  404.             sleep.second(秒 = 1);
  405.             return true;
  406.         }
  407.     }

  408.     // 5. 查找消息列表底部区域内的ImageView(箭头图标)
  409.     var ivPattern = /<node[^>]*?class="android\.widget\.ImageView"[^>]*?clickable="true"[^>]*?\/?>/g;
  410.     var ivMatch;
  411.     while ((ivMatch = ivPattern.exec(xmlStr)) !== null) {
  412.         var ivNode = ivMatch[0];
  413.         var boundsMatch = ivNode.match(/bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/);
  414.         if (!boundsMatch) continue;
  415.         
  416.         var ivx1 = parseInt(boundsMatch[1]);
  417.         var ivy1 = parseInt(boundsMatch[2]);
  418.         var ivx2 = parseInt(boundsMatch[3]);
  419.         var ivy2 = parseInt(boundsMatch[4]);
  420.         
  421.         var 在底部 = (ivy1 > 屏幕高 * 0.5);
  422.         var 在中间 = (ivx1 > 屏幕宽 * 0.3 && ivx2 < 屏幕宽 * 0.7);
  423.         
  424.         if (在底部 && 在中间) {
  425.             var centerX = (ivx1 + ivx2) / 2;
  426.             var centerY = (ivy1 + ivy2) / 2;
  427.             agent.click(centerX, centerY);
  428.             print.log("✓ 已点击ImageView(箭头图标),坐标(" + Math.round(centerX) + "," + Math.round(centerY) + ")");
  429.             sleep.second(秒 = 2);
  430.             return true;
  431.         }
  432.     }

  433.     // 6. 最终兜底:点击消息列表底部中心位置(展开箭头通常在这里)
  434.     var rvPattern2 = /<node[^>]*?class="androidx\.recyclerview\.widget\.RecyclerView"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  435.     var rvMatch2;
  436.     while ((rvMatch2 = rvPattern2.exec(xmlStr)) !== null) {
  437.         var rx1 = parseInt(rvMatch2[1]);
  438.         var ry1 = parseInt(rvMatch2[2]);
  439.         var rx2 = parseInt(rvMatch2[3]);
  440.         var ry2 = parseInt(rvMatch2[4]);
  441.         var 高度 = ry2 - ry1;
  442.         if (高度 > 500) {
  443.             var centerX = (rx1 + rx2) / 2;
  444.             var bottomY = ry2 - 60;
  445.             agent.click(centerX, bottomY);
  446.             print.log("✓ 已点击消息列表底部中心(兜底展开),坐标(" + Math.round(centerX) + "," + Math.round(bottomY) + ")");
  447.             sleep.second(秒 = 2);
  448.             return true;
  449.         }
  450.     }

  451.     var pctX = 屏幕宽 / 2;
  452.     var pctY = 屏幕高 * 0.75;
  453.     agent.click(pctX, pctY);
  454.     print.log("✓ 已点击屏幕底部中间(最终兜底),坐标(" + Math.round(pctX) + "," + Math.round(pctY) + ")");
  455.     sleep.second(秒 = 1);
  456.     return true;
  457. }

  458. // 从XML解析 RecyclerView 的边界,然后在其中滑动到底部
  459. function 滑动消息列表到底部(xml) {
  460.     var xmlStr = "" + xml;

  461.     var rvPattern = /<node[^>]*?class="androidx\.recyclerview\.widget\.RecyclerView"[^>]*?bounds="\[(\d+),(\d+)\]\[(\d+),(\d+)\]"/g;
  462.     var rvMatch;

  463.     while ((rvMatch = rvPattern.exec(xmlStr)) !== null) {
  464.         var rx1 = parseInt(rvMatch[1]);
  465.         var ry1 = parseInt(rvMatch[2]);
  466.         var rx2 = parseInt(rvMatch[3]);
  467.         var ry2 = parseInt(rvMatch[4]);
  468.         var 高度 = ry2 - ry1;

  469.         if (高度 > 500) {
  470.             var startX = (rx1 + rx2) / 2;
  471.             var startY = ry1 + (ry2 - ry1) * 0.2;
  472.             var endX = startX;
  473.             var endY = ry1 + (ry2 - ry1) * 0.8;

  474.             agent.swip(startX, startY, endX, endY, 500);
  475.             print.log("✓ 已在RecyclerView内滑动,区域[" + rx1 + "," + ry1 + "][" + rx2 + "," + ry2 + "]");
  476.             return;
  477.         }
  478.     }

  479.     print.log("⚠ 未找到RecyclerView,使用屏幕百分比滑动");
  480.     agent.swip(屏幕宽 / 2, 屏幕高 * 0.3, 屏幕宽 / 2, 屏幕高 * 0.8, 500);
  481. }

  482. // 等待AI回答完成
  483. // 逻辑:
  484. //   阶段1:等待新回答出现(文本变化)
  485. //   阶段2:点击展开按钮(在消息列表底部)
  486. //   阶段3:动态检测回答是否完成(连续2次检查文本不变,则认为完成)
  487. // 参数:发送前的最后一条AI回答文本(用于对比检测新回答)
  488. // 返回:新回答的文本内容
  489. function 等待AI回答完成(发送前的最后文本) {
  490.     var 已耗时 = 0;
  491.     var 检查间隔秒 = 2;
  492.     var 已检测到新回答 = false;
  493.     var 已点击展开按钮 = false;
  494.     var 上次文本 = "";
  495.     var 文本不变次数 = 0;
  496.     var 已检测到思考完成 = false;

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

  500.         var xml = 获取UI();
  501.         var xmlStr = "" + xml;

  502.         if (!已检测到新回答) {
  503.             // 阶段1:等待新回答出现
  504.             var 宽松列表 = 采集AI回答列表(xml, false);
  505.             if (宽松列表.length === 0) {
  506.                 continue;
  507.             }
  508.             var 当前最后文本 = 宽松列表[宽松列表.length - 1];
  509.             if (当前最后文本 !== 发送前的最后文本 && 字符串长度(当前最后文本) > 0) {
  510.                 print.log("✓ 检测到新回答出现(" + 已耗时 + "秒)");
  511.                 已检测到新回答 = true;
  512.                 上次文本 = 当前最后文本;
  513.             }
  514.         } else {
  515.             // 阶段2和3:点击展开按钮并检测完成
  516.             var 当前列表 = 采集AI回答列表(xml, false);
  517.             var 当前文本 = "";
  518.             if (当前列表.length > 0) {
  519.                 当前文本 = 当前列表[当前列表.length - 1];
  520.             }

  521.             // 检查是否完成思考(宽松条件)
  522.             if (!已检测到思考完成 && (xmlStr.indexOf("参考") !== -1)) {
  523.                 print.log("✓ 检测到AI思考完成(" + 已耗时 + "秒)");
  524.                 已检测到思考完成 = true;
  525.             }

  526.             // 点击展开按钮(在检测到思考完成后立即点击)
  527.             if (!已点击展开按钮 && 已检测到思考完成) {
  528.                 查找并点击展开按钮(xml);
  529.                 已点击展开按钮 = true;
  530.                 print.log("✓ 已点击展开按钮");
  531.             }

  532.             // 如果没检测到思考完成,但文本很长,也尝试点击展开
  533.             if (!已点击展开按钮 && !已检测到思考完成 && 字符串长度(当前文本) > 100 && 已耗时 >= 8) {
  534.                 查找并点击展开按钮(xml);
  535.                 已点击展开按钮 = true;
  536.                 print.log("✓ 文本较长,尝试点击展开按钮");
  537.             }

  538.             // 检查文本是否停止变化
  539.             if (当前文本 === 上次文本) {
  540.                 文本不变次数++;
  541.             } else {
  542.                 文本不变次数 = 0;
  543.                 上次文本 = 当前文本;
  544.             }

  545.             // 判断完成条件:
  546.             // 1. 文本连续2次不变
  547.             // 2. 且文本长度大于50
  548.             // 3. 且已等待至少6秒(确保展开后有时间显示完整内容)
  549.             if (文本不变次数 >= 2 && 字符串长度(当前文本) > 50 && 已耗时 >= 6) {
  550.                 print.log("✓ 检测到回答完成(文本连续不变),返回采集结果");
  551.                 return 当前文本;
  552.             }

  553.             // 如果文本很短但停止变化很久,也返回
  554.             if (文本不变次数 >= 4 && 字符串长度(当前文本) > 10 && 已耗时 >= 10) {
  555.                 print.log("✓ 文本停止变化已久,返回采集结果");
  556.                 return 当前文本;
  557.             }
  558.         }
  559.     }

  560.     // 超时兜底:尽量返回当前能采集到的最后一条回答
  561.     print.log("⚠ 等待AI回答超时(" + 等待回答超时秒 + "秒),尝试返回当前内容");
  562.     var xml = 获取UI();
  563.     var 兜底列表 = 采集AI回答列表(xml, true);
  564.     if (兜底列表.length > 0) {
  565.         var 兜底文本 = 兜底列表[兜底列表.length - 1];
  566.         if (兜底文本 !== 发送前的最后文本) {
  567.             print.log("✓ 超时兜底:返回当前采集到的回答");
  568.             return 兜底文本;
  569.         }
  570.     }
  571.     var 兜底宽松 = 采集AI回答列表(xml, false);
  572.     if (兜底宽松.length > 0) {
  573.         var 兜底文本2 = 兜底宽松[兜底宽松.length - 1];
  574.         if (兜底文本2 !== 发送前的最后文本 && 字符串长度(兜底文本2) > 5) {
  575.             print.log("✓ 超时兜底(宽松):返回当前采集到的回答");
  576.             return 兜底文本2;
  577.         }
  578.     }
  579.     return null;
  580. }

  581. // 获取当前页面最后一条AI回答文本(用于发送前记录基线)
  582. function 获取当前最后AI回答(xml) {
  583.     var 回答列表 = 采集AI回答列表(xml);
  584.     if (回答列表.length === 0) return "";
  585.     return 回答列表[回答列表.length - 1];
  586. }

  587. // 格式化对话内容输出(TXT格式)
  588. function 格式化对话(对话列表) {
  589.     var result = "========== 千问对话记录 ==========\n";
  590.     result += "采集时间:" + new Date().toString() + "\n";
  591.     result += "对话轮数:" + 对话列表.length + "\n";
  592.     result += "==================================\n\n";
  593.    
  594.     for (var i = 0; i < 对话列表.length; i++) {
  595.         result += "【" + 对话列表[i].角色 + "】\n";
  596.         result += 对话列表[i].内容 + "\n";
  597.         result += "----------------------------------\n";
  598.         if (i < 对话列表.length - 1) {
  599.             result += "\n";
  600.         }
  601.     }
  602.    
  603.     return result;
  604. }

  605. // 写入文件(TXT格式,GBK编码)
  606. function 写入文件(文件路径, 内容) {
  607.     var javaStr = new java.lang.String(内容);
  608.    
  609.     try {
  610.         var fos = new java.io.FileOutputStream(文件路径);
  611.         fos.write(javaStr.getBytes("GBK"));
  612.         fos.close();
  613.         
  614.         print.log("✓ 已写入文件(TXT格式,GBK编码):" + 文件路径);
  615.         
  616.         var catResult = agent.shell("cat " + 文件路径 + " | head -2");
  617.         print.log("✓ cat验证结果:" + catResult);
  618.         
  619.         return true;
  620.     } catch (e) {
  621.         print.log("⚠ FileOutputStream写入异常:" + e.message);
  622.     }

  623.     try {
  624.         var base64Content = java.util.Base64.getEncoder().encodeToString(javaStr.getBytes("GBK"));
  625.         agent.shell("echo '" + base64Content + "' | base64 -d > " + 文件路径);
  626.         
  627.         print.log("✓ 已通过base64写入文件(GBK):" + 文件路径);
  628.         
  629.         var catResult = agent.shell("cat " + 文件路径 + " | head -2");
  630.         print.log("✓ cat验证结果:" + catResult);
  631.         
  632.         return true;
  633.     } catch (e2) {
  634.         print.log("⚠ base64写入异常:" + e2.message);
  635.     }

  636.     try {
  637.         var fos2 = new java.io.FileOutputStream(文件路径);
  638.         fos2.write(javaStr.getBytes("UTF-8"));
  639.         fos2.close();
  640.         
  641.         print.log("✓ 已通过FileOutputStream写入文件(UTF-8):" + 文件路径);
  642.         
  643.         return true;
  644.     } catch (e3) {
  645.         print.log("⚠ UTF-8写入异常:" + e3.message);
  646.     }

  647.     print.log("✗ 写入文件失败:" + 文件路径);
  648.     return false;
  649. }

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

  651. // 步骤1:启动千问APP
  652. print.log("\n========== 步骤1:启动千问APP ==========");
  653. try {
  654.     app.openApp(千问包名);
  655.     print.log("✓ 已启动千问");
  656. } catch (e) {
  657.     print.log("⚠ 启动失败:" + e.message);
  658. }
  659. sleep.second(秒 = 5);

  660. // 步骤2:确认进入对话页面
  661. print.log("\n========== 步骤2:确认进入对话页面 ==========");
  662. var xml = 获取UI();
  663. var hasRecyclerView = (xml.indexOf("androidx.recyclerview.widget.RecyclerView") !== -1);
  664. if (!hasRecyclerView) {
  665.     print.log("⚠ 当前页面可能不是千问对话页,再次等待");
  666.     sleep.second(秒 = 3);
  667.     xml = 获取UI();
  668.     hasRecyclerView = (xml.indexOf("androidx.recyclerview.widget.RecyclerView") !== -1);
  669. }

  670. if (hasRecyclerView) {
  671.     print.log("✓ 已进入千问对话页面");
  672. } else {
  673.     print.log("⚠ 未检测到消息列表,继续尝试");
  674. }

  675. // 步骤3:循环发送问题并采集回答
  676. print.log("\n========== 步骤3:循环发送问题并采集回答 ==========");

  677. // 完整对话列表(包含用户问题和AI回答)
  678. var 完整对话 = [];

  679. // 获取发送第一个问题前的最后AI回答文本(作为基线,用于检测新回答)
  680. var 初始最后文本 = 获取当前最后AI回答(xml);
  681. print.log("✓ 初始页面最后一条AI回答长度:" + 字符串长度(初始最后文本));

  682. // 开始发送问题
  683. for (var q = 0; q < 要发送的问题列表.length; q++) {
  684.     var 当前问题 = 要发送的问题列表[q];
  685.     print.log("\n---- 第 " + (q + 1) + " / " + 要发送的问题列表.length + " 个问题 ----");
  686.     print.log("问题:" + 当前问题);

  687.     // 3.1 重新获取UI,定位输入框
  688.     xml = 获取UI();
  689.     var 输入框 = 查找输入框中心(xml);
  690.     if (!输入框) {
  691.         print.log("⚠ 未找到输入框,跳过此问题");
  692.         sleep.second(秒 = 问题间隔秒);
  693.         continue;
  694.     }

  695.     // 3.2 记录发送前的最后一条AI回答文本(作为检测新回答的基线)
  696.     var 发送前最后文本 = 获取当前最后AI回答(xml);

  697.     // 3.3 点击输入框获取焦点
  698.     agent.click(输入框.x, 输入框.y);
  699.     sleep.second(秒 = 1);

  700.     // 3.4 粘贴问题文本
  701.     粘贴文本(当前问题);

  702.     // 3.5 重新获取UI,查找发送按钮
  703.     xml = 获取UI();
  704.     var 发送按钮 = 查找发送按钮中心(xml);

  705.     if (发送按钮) {
  706.         agent.click(发送按钮.x, 发送按钮.y);
  707.         print.log("✓ 已点击发送按钮");
  708.     } else {
  709.         // 兜底:按回车键发送
  710.         agent.shell("input keyevent 66");
  711.         print.log("⚠ 未找到发送按钮,已尝试按回车发送");
  712.     }

  713.     // 3.6 记录用户问题
  714.     完整对话.push({
  715.         角色: "用户",
  716.         内容: 当前问题
  717.     });

  718.     // 3.7 等待AI回答完成(基于"最后一条回答文本变化"判断,不依赖数量递增)
  719.     print.log("等待AI回答,发送前最后文本长度:" + 字符串长度(发送前最后文本));

  720.     var 新回答文本 = 等待AI回答完成(发送前最后文本);
  721.     if (新回答文本 && 字符串长度(新回答文本) > 0) {
  722.         完整对话.push({
  723.             角色: "AI",
  724.             内容: 新回答文本
  725.         });
  726.         print.log("✓ 采集到新回答,当前总对话条数:" + 完整对话.length);
  727.         print.log("--- 采集内容开始 ---");
  728.         print.log(新回答文本);
  729.         print.log("--- 采集内容结束 ---");
  730.     } else {
  731.         print.log("⚠ 未能采集到新回答");
  732.     }

  733.     sleep.second(秒 = 问题间隔秒);
  734. }

  735. // 步骤4:保存对话到文件
  736. print.log("\n========== 步骤4:保存对话到文件 ==========");
  737. var 输出内容 = 格式化对话(完整对话);
  738. var 写入成功 = 写入文件(输出文件路径, 输出内容);

  739. if (写入成功) {
  740.     print.log("✓ 对话已保存到:" + 输出文件路径);
  741.     print.log("✓ 总对话条数:" + 完整对话.length);
  742. } else {
  743.     print.log("✗ 保存失败,请检查存储权限");
  744. }

  745. // 步骤5:打印全部采集到的对话内容
  746. print.log("\n========== 全部采集内容 ==========");
  747. print.log(输出内容);
  748. print.log("========== 内容结束 ==========");

  749. print.log("\n===== 千问对话采集流程结束 =====");
复制代码



unto豆包识别验证码加拖动验证码示例nextnocontent
回复

使用道具 举报

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

本版积分规则

相关导读
信息发布软件示例千问自动采集文章保存记事本
示例千问自动采集文章保存记事本
信息发布软件豆包识别验证码加拖动验证码示例
豆包识别验证码加拖动验证码示例
信息发布软件豆包对话采集示例
豆包对话采集示例
信息发布软件启动自动百度贴吧发图片
启动自动百度贴吧发图片
信息发布软件自动百度贴吧示例
自动百度贴吧示例
信息发布软件代理模式简书自动流程
代理模式简书自动流程
信息发布软件启动极速版任务页看小说赚钱自动阅读
启动极速版任务页看小说赚钱自动阅读
信息发布软件agent代理模式功能小结
agent代理模式功能小结
信息发布软件完整苹果IOS小脚本文本输入与粘贴流程
完整苹果IOS小脚本文本输入与粘贴流程
信息发布软件AIWROK使用activity列表开关与进度条的协同交互
AIWROK使用activity列表开关与进度条的协同交互
群发软件苹果脚本找图后Detect对象各种方法演示
苹果脚本找图后Detect对象各种方法演示
群发软件苹果脚本网络API监控与数据管理工具
苹果脚本网络API监控与数据管理工具
群发软件IOS苹果脚本TXT文件读写H5日志打印完整示例
IOS苹果脚本TXT文件读写H5日志打印完整示例
群发软件AIWROK软件演示多线程创建暂停恢复
AIWROK软件演示多线程创建暂停恢复
群发软件AIWROK软件定时检查页面状态防止卡死技巧
AIWROK软件定时检查页面状态防止卡死技巧
群发软件安卓脚本runTime相关功能示例
安卓脚本runTime相关功能示例
群发软件floatUI实例秒显示秒关闭吐司功能
floatUI实例秒显示秒关闭吐司功能
群发软件苹果脚本HID多行实例粘帖板示例
苹果脚本HID多行实例粘帖板示例
群发软件安卓脚本HID节点查找完整方法示例
HID节点查找完整方法示例
群发软件AIWROK软件框架的抖音自动化营销系统
AIWROK软件框架的抖音自动化营销系统
群发软件赛博朋克任务控制中心H5示例
赛博朋克任务控制中心H5示例
群发软件苹果脚本现代深色UI设计风格
现代深色UI设计风格
群发软件AIWROK软件智能任务监控悬浮窗
AIWROK软件智能任务监控悬浮窗
群发软件AIWROK软件事件监听示例
AIWROK软件事件监听示例
群发软件QZ掘金原生UI界面
QZ掘金原生UI界面
群发软件安卓脚本auto方法完整示例
安卓脚本auto方法完整示例
群发软件安卓脚本暂停弹出确认对话框
安卓脚本暂停弹出确认对话框
群发软件苹果iOS脚本天气信息查询工具
苹果iOS脚本天气信息查询工具
群发软件安卓脚本简化版H5日志输出窗口
安卓脚本简化版H5日志输出窗口
群发软件安卓脚本简化版H5日志输出窗口
安卓脚本简化版H5日志输出窗口
群发软件安卓脚本应用重置、代理模式监控及补丁升级
安卓脚本应用重置、代理模式监控及补丁升级
群发软件安卓脚本里的打开关闭安装以及卡密授权信息
安卓脚本里的打开关闭安装以及卡密授权信息
群发软件AIWROK软件脚本GET下载文件并检测0KB工具
AIWROK软件脚本GET下载文件并检测0KB工具
群发软件安卓脚本HID按键方法完整示例
安卓脚本HID按键方法完整示例
群发软件AIWROK软件键鼠HID滑动所有方法功能演示
AIWROK软件键鼠HID滑动所有方法功能演示
群发软件苹果脚本里HID的5种滑动方法的使用
苹果脚本里HID的5种滑动方法的使用
群发软件苹果脚本示例7种不同的OCR识别和点击方法
苹果脚本示例7种不同的OCR识别和点击方法
群发软件AIWROK软件安卓脚本FTP上传下载例子
AIWROK软件安卓脚本FTP上传下载例子
群发软件AIWROK软件脚本JSON转换示例
AIWROK软件脚本JSON转换示例
群发软件AIWROK软件运算符高级应用实例
AIWROK软件运算符高级应用实例
群发软件JavaScript语法小示例
JavaScript语法小示例
群发软件展示JavaScript各种语句标识符的实际应用
展示JavaScript各种语句标识符的实际应用
群发软件AIWROK条件语句实用示例智能活动推荐系统
AIWROK条件语句实用示例智能活动推荐系统
群发软件AIWROK软件示例数组方法实战应用
AIWROK软件示例数组方法实战应用
群发软件示例JavaScript的 try-catch-finally-throw用法
示例JavaScript的 try-catch-finally-throw用法
群发软件JavaScript 高级错误处理实战示例
JavaScript 高级错误处理实战示例
群发软件安卓脚本AIWROK软件示例JS函数高级用法
安卓脚本AIWROK软件示例JS函数高级用法
群发软件AIWROK环境JavaScript编码规范完整示例
AIWROK环境JavaScript编码规范完整示例
群发软件安卓脚本示例实时截图判断页面变化
安卓脚本示例实时截图判断页面变化
群发软件苹果脚本7种不同的OCR识别
苹果脚本7种不同的OCR识别
群发软件安卓脚本多变的function用法
安卓脚本多变的function用法
群发软件苹果脚本示例Config配置H5集成
苹果脚本示例Config配置H5集成
群发软件安卓脚本类型判断与Boolean对象综合示例
安卓脚本类型判断与Boolean对象综合示例
群发软件线程全局变量H5可视化控制台
线程全局变量H5可视化控制台
群发软件秒吐司快速显示和关闭的UI提示窗口
秒吐司快速显示和关闭的UI提示窗口
群发软件苹果脚本里H5 里的 window.at.callFun 示例
苹果脚本里H5 里的 window.at.callFun 示例
群发软件H5日志打印运行过程例子
H5日志打印运行过程例子
群发软件AIWROK软件字符串方法实用案例
AIWROK软件字符串方法实用案例
群发软件HID贝塞尔曲线运动控制器
HID贝塞尔曲线运动控制器
群发软件AIWROK苹果脚本sleep方法综合实战示例
AIWROK苹果脚本sleep方法综合实战示例
群发软件苹果脚本Line控件的多种创意用法和实际应用场景
苹果脚本Line控件的多种创意用法和实际应用场景
群发软件苹果脚本toast高级应用综合示例
苹果脚本toast高级应用综合示例
群发软件苹果智能OCR自动化助手
苹果智能OCR自动化助手
群发软件苹果脚本UI超快速点击示例
苹果脚本UI超快速点击示例
群发软件展示时间戳的各种复杂处理方法
展示时间戳的各种复杂处理方法

QQ|( 京ICP备09078825号 )

本网站信息发布软件,是可以发布论坛,发送信息到各大博客,各大b2b软件自动发布,好不夸张的说:只要手工能发在电脑打开IE能发的网站,用这个宣传软件就可以仿制动作,进行推送发到您想发送的B2B网站或是信息发布平台上,不管是后台,还是前台,都可以进行最方便的广告发布,这个广告发布软件,可以按月购买,还可以试用软件,对网站的验证码也可以完全自动对信息发布,让客户自动找上门,使企业轻松实现b2b发布,这个信息发布软件,均是本站原创正版开发,拥有正版的血统,想要新功能,欢迎提意见给我,一好的分类信息群发软件在手,舍我其谁。QQ896757558

GMT+8, 2026-7-15 08:50 , Processed in 11.319603 second(s), 49 queries .

宣传软件--信息发布软件--b2b软件广告发布软件

快速回复 返回顶部 返回列表