开发日志251210

date
Dec 10, 2025
slug
开发日志251210
status
Published
tags
计算机
AI
summary
给抖音收尾 然后开始处理小红书
type
Post

抖音广告跳过

这个功能实现起来比较简单
//跳过广告
// 1. 定义“广告特征”与“处理动作”的对应关系
const adRules = [
    // 每条规则格式: [识别特征数组, 需要点击的按钮文字]
    { keywords: ['发现抖音朋友', '收到朋友'], button: '拒绝' },
    { keywords: ['新版本内测邀请', '检测到更新'], button: '以后再说' },
    { keywords: ['青少年模式', '青少年'], button: '我知道了' },
    { keywords: ['未成年人模式', '未成年'], button: '关闭' },
    { keywords: ['上滑继续看视频'], button: '残忍拒绝' }
];

// 2. 统一的广告监控与处理主循环
threads.start(function () {
    for (let round = 1; round <= 5; round++) {
        let handled = false; // 标记本轮是否处理了弹窗
        // 遍历所有规则
        for (let rule of adRules) {
            for (let keyword of rule.keywords) {
                // 如果屏幕上有符合这个规则的文字
                if (text(keyword).exists() || textContains(keyword).exists()) {
                    logInfo.i(`发现弹窗: ${keyword},尝试点击: ${rule.button}`);
                    if (clickByText(rule.button)) {
                        handled = true;
                        sleepRand(1000, 1500);
                        break; // 跳出当前规则的关键词循环
                    }
                }
            }
            if (handled) {
                break; // 如果已处理一个弹窗,跳出规则遍历,进入下一轮监控
            }
        }
        sleepRand(1000, 1500);
    }
});

// 3. 工具函数:通过按钮文字点击 (与之前相同)
function clickByText(buttonText) {
    var btn = text(buttonText).findOne(1000);
    if (btn) {
        btn.click();
        sleepRand(200, 500);
        return true;
    }
    toastLog(`未找到按钮: ${buttonText}`);
    return false;
}

全部停止功能修复

这个也比较简单 昨天忘记修改这段代码了 直接获取 taskStatusforEach() 方法处理即可

小红书

今天开始小红书环节 刚刚注册好一系列账号 现在考虑如何取做小红书脚本
首先小红书主体是信息流
双列信息流
双列信息流
视频流
视频流
信息流中有视频内容和帖子内容 进入帖子后内容类似抖音图片 视频则类似抖音视频 有点赞 评论等控件 评论操作也与抖音类似
但是 需要注意的是 由于信息流的存在 导致 执行一次行为 的链条会比较复杂
例如刷视频状态 需要通过 任意方法进入某视频 然后 才能进行类似抖音的刷视频流程 同时刷完视频后应该 返回初始页面 以保证流程:
graph LR
  A[信息流界面] -->D{前处理环节}--> B[视频流界面] --执行刷视频/评论-->B-->E{后处理环节}--需要返回信息流-->A
  E--不需要返回信息流-->B
  A--执行帖子评论-->A
  D-->C[发视频界面]--执行发视频-->C-->E
notion image
然而抖音也需要这种处理 但是抖音脚本部分只做了执行任务的功能
抖音方面也同理
graph LR
  A[通用视频界面] -->D{前处理环节}--> B[同城视频流界面] --执行刷视频/评论-->B-->E{后处理环节}--需要返回推荐页-->A
  E--不需要返回-->B
  A--执行刷视频/评论-->A
  D-->C[发视频界面]--执行发视频-->C-->E
此外还要调整一下文件结构 这才写多少就开始堆屎山了 └├─├
原先的结构是:
index.html
utils/  #功能组件
└─taskRunner.js  #任务执行器
functions/  #任务脚本
├─tiktok-browse.js #抖音看视频脚本
├─tiktok-comment.js #抖音评论脚本
├─xiaohongshu-browse.js #小红书刷xx脚本
└─common.js  #通用函数脚本
platform/  #平台脚本选择器
├─douyin.js #抖音
└─xiaohongshu.js  #小红书
如果要加前后处理就不能放在所有任务脚本一起了 只能 按平台分开放
需要分离 跳过广告 , 进入指定页面 , 执行搜索 等功能作为前处理依次执行 返回一个前处理结果 然后再根据前处理结果执行 主要脚本 并返回整个执行结果
需要注意的是 前处理结果可以 预识别视频内容 读取视频作者和标题,并判断本次是否需要点赞/评论 当需要时调用的 主要脚本 仅执行一次当前行为 并不做多余的判断 例如前处理获得视频作者和标题后 判断需要点赞 则调用 点赞脚本 只进行一次点赞操作 如果点赞成功则返回成功 否则失败 评论同理 不在脚本内处理概率判断
那么评中评呢 以及 评论点赞
问了下ai 保存下结果 明天研究
DS
你遇到的困境非常经典,本质是在“原子操作”和“复合任务”之间寻找灵活的编排层。问题的核心是:前处理层需要动态判断接下来要执行哪个(或哪几个)原子脚本,而不是固定搭配。

🔧 解决方案:设计一个“上下文感知”的动态任务编排器

你需要一个智能路由器,它能根据前处理产生的上下文(Context),动态决定后续的执行链。这个“上下文”里就包含了“是否需要点赞”、“是否需要评论”、“评论给谁”等关键决策。

第一步:定义标准的上下文对象

让所有前处理脚本和原子脚本,都接收和返回一个标准化的上下文对象,作为信息传递的载体。
// 定义任务执行的上下文模型
const taskContext = {
    // 由前处理脚本填充
    currentPage: 'search_result', // 当前所在页面:'home'(推荐流)、'city'(同城)、'search'(搜索结果)、'video_detail'(视频页)
    targetVideo: {
        id: 'video_123',
        author: '某作者',
        title: '某标题',
        // 前处理脚本可以通过图像识别/OCR将信息提取到这里
    },
    targetComment: {
        id: 'comment_456',
        author: '某用户',
        content: '这条评论很好',
        // 如果需要评论互动,这里就是目标
    },
    // 决策结果
    decisions: {
        needLikeVideo: true,     // 是否需要给视频点赞
        needCommentVideo: true,  // 是否需要评论视频
        commentTemplate: '好评模板1', // 使用哪个评论模板
        needLikeComment: true,   // 是否需要给评论点赞
        needReplyComment: false  // 是否需要回复评论
    },
    // 执行结果
    results: {
        likeVideoSuccess: false,
        commentVideoSuccess: false,
        likeCommentSuccess: false
    }
};

第二步:创建可插拔的“决策器” (Decision Maker)

概率判断条件判断从脚本中彻底抽离,形成独立的决策模块。决策器读取上下文,并输出更新了decisions字段的上下文
// deciders/ 目录 - 存放各种决策器
// deciders/videoActionDecider.js
export function decideVideoActions(context) {
    const decisions = context.decisions;
    // 示例:基于视频作者或标题的复杂规则
    if (context.targetVideo.author.includes('广告')) {
        decisions.needLikeVideo = false;
        decisions.needCommentVideo = false;
    } else {
        decisions.needLikeVideo = Math.random() < 0.7; // 70%概率点赞
        decisions.needCommentVideo = Math.random() < 0.3; // 30%概率评论
    }
    return context; // 返回更新了decisions的上下文
}

// deciders/commentActionDecider.js
export function decideCommentActions(context) {
    const decisions = context.decisions;
    // 示例:给热门评论点赞
    if (context.targetComment && context.targetComment.likes > 100) {
        decisions.needLikeComment = true;
    }
    return context;
}

第三步:改造前处理脚本为“场景构建器”

前处理脚本的职责变为:1. 跳转到指定场景;2. 为上下文填充初始数据
// preprocessors/searchAndSelectProcessor.js
export async function process(context, device) {
    // 1. 执行一系列前置动作
    await openApp(device);
    await skipAd(device);
    await goToSearchPage(device);
    await inputKeyword(device, '目标关键词');

    // 2. 识别并选取第一个视频,提取信息
    const firstVideoInfo = await identifyFirstVideo(device);
    // 3. 更新上下文
    context.currentPage = 'search_result';
    context.targetVideo = firstVideoInfo;
    // decisions 留空,交给决策器

    console.log(`[前处理] 已进入搜索页,选中视频:${firstVideoInfo.title}`);
    return context; // 返回构建好的上下文
}

第四步:原子脚本保持纯粹

原子脚本只做一件事,并从上下文中获取指令。
// functions/douyin_like_video.js
export async function execute(context, device) {
    // 只负责点赞,不判断该不该点
    const result = await likeTheCurrentVideo(device);
    context.results.likeVideoSuccess = result;
    return context;
}

第五步:核心编排引擎

这是大脑,负责按顺序串联:场景构建 -> 决策 -> 执行
// orchestrators/ 目录 - 核心编排引擎
// orchestrators/mainOrchestrator.js
import { process as searchAndSelect } from '../preprocessors/searchAndSelectProcessor.js';
import { decideVideoActions } from '../deciders/videoActionDecider.js';
import { decideCommentActions } from '../deciders/commentActionDecider.js';
import { execute as likeVideo } from '../functions/douyin_like_video.js';
import { execute as commentVideo } from '../functions/douyin_comment_video.js';
import { execute as likeComment } from '../functions/douyin_like_comment.js';

export async function runDynamicTask(device, taskConfig) {
    // 1. 初始化上下文
    let context = { currentPage: '', targetVideo: null, decisions: {}, results: {} };

    // 2. 【场景构建】根据任务类型,选择不同的前处理器
    if (taskConfig.type === 'SEARCH_AND_INTERACT') {
        context = await searchAndSelect(context, device);
    } else if (taskConfig.type === 'HOMEPAGE_BROWSE') {
        context = await anotherPreprocessor(context, device);
    }

    // 3. 【决策】运行一系列决策器,决定做什么
    context = decideVideoActions(context);
    context = decideCommentActions(context);

    // 4. 【动态执行】根据决策结果,动态调用原子脚本
    if (context.decisions.needLikeVideo) {
        context = await likeVideo(context, device);
    }
    if (context.decisions.needCommentVideo) {
        context = await commentVideo(context, device);
    }
    if (context.targetComment && context.decisions.needLikeComment) {
        context = await likeComment(context, device);
    }

    // 5. 返回完整的执行结果上下文
    console.log('任务完成,最终结果:', context.results);
    return context;
}

📁 最终的优化目录结构

你的项目根目录
├── index.html
├── main.js                       # 系统入口
├── utils/taskRunner.js           # 基础执行器(可能被调用)
├── orchestrators/                # 【新增】核心编排层
│   └── mainOrchestrator.js       # 动态任务大脑
├── preprocessors/                # 【场景构建层】
│   ├── searchAndSelectProcessor.js
│   ├── homepageProcessor.js
│   └── cityPageProcessor.js
├── deciders/                     # 【决策层】
│   ├── videoActionDecider.js
│   └── commentActionDecider.js
├── functions/                    # 【原子操作层】保持纯净
│   ├── douyin_like_video.js
│   ├── douyin_comment_video.js
│   ├── douyin_like_comment.js
│   └── ...
└── platform/                     # 【平台适配层】调用编排器
    ├── douyin.js                # 调用 orchestrators/mainOrchestrator.runDynamicTask(...)
    └── xiaohongshu.js

💡 这个模式如何解决你的问题?

  1. 前处理复用searchAndSelectProcessor.js 这样的前处理脚本,可以为“搜索后刷视频”、“搜索后评论”等多种后续任务提供统一的场景构建服务,无需重复编写。
  1. 动态决策链:通过独立的决策器,你可以组合出无限可能:“给视频点赞” -> “给视频评论” -> “给这个评论点赞” -> “再回复一条”。只需按顺序调用对应的决策器和原子脚本。
  1. 原子脚本极致纯粹:每个脚本只做一件小事(点赞、评论),不包含任何“是否应该做”的判断逻辑。判断逻辑全部上移到可配置、可复用的决策器中。
总结:你不需要为每种组合写一个前处理,而是需要:
  1. 写不同的“场景构建器”(前处理)来进入不同页面。
  1. 写不同的“决策器” 来定义在不同场景下做什么动作的组合与概率。
  1. 写一个“编排引擎” 来把1和2,以及纯粹的原子脚本,像搭积木一样组合起来。
这样,当你想增加“给评论的评论点赞”这个新行为时,你只需要:1)写一个 decideReplyToCommentDecider.js 决策器;2) 确保有一个能获取到targetComment上下文的前处理器;3)在编排引擎中按需调用它。完全不需要改动任何原子脚本或重写前处理。
Grok

问题分析与整体思路

你当前的痛点很清楚:原脚本是“简单线性流程”(刷视频 → 概率点赞/评论),但现在需要支持更复杂的场景(如进入同城页、搜索特定视频),并且要分离“前处理”(pre-processing,如跳过广告、导航页面、预识别视频)和“主要脚本”(core actions,如点赞、评论)。关键挑战是:
  • 前处理需要“智能判断”(e.g., 基于视频作者/标题决定是否点赞/评论),但主要脚本要保持“哑巴”(只执行一次动作,不带判断)。
  • 如果引入概率(e.g., 评论后概率点赞)或组合(e.g., 点赞 + 评论评论),前处理就容易爆炸:每种组合都需要自定义前处理,导致代码重复和维护噩梦。
我的建议:采用“配置驱动的任务管道(Pipeline)”架构。核心思想:
  • 统一前处理层:所有任务共享一个前处理管道(pipeline),这是一个函数数组,按序执行(e.g., 跳过广告 → 进入页面 → 搜索 → 预识别视频)。
  • 规则引擎:在前处理末尾,用一个“决策器”(decider)基于配置规则(e.g., 概率、条件)动态生成“动作列表”(actions list),如 [点赞, 评论, 评论后点赞]。
  • 主要脚本:只是一个“执行器”(executor),接收动作列表,按序调用独立的“原子动作函数”(e.g., likeVideo() 只点赞一次,不带任何判断)。
  • 整个流程:前处理返回 { success: true, videoInfo: {...}, actionsToRun: [...] },然后主要执行器跑 actionsToRun,返回 { preResult, mainResult }。
优点:
  • 灵活组合:不用为每种情况写新前处理,只改配置(e.g., JSON 对象)就能实现“评论后概率点赞”或“给评论评论”。
  • 解耦:原子动作函数保持纯净(只做一件事),判断全在前处理决策器里。
  • 可扩展:以后加新前处理(如“检查网络”)或新动作(如“转发”)只需加函数到管道/列表。
  • 整个结果:返回包含前处理 + 主要执行的完整日志/结果,便于群控系统监控。
缺点:初始配置稍复杂,但远胜于写 N 个自定义脚本。

推荐架构设计

1. 核心组件定义

  • 前处理管道 (prePipeline):一个函数数组,每个函数返回 { success: bool, data: {...} } 或抛错。失败时中断管道。
    • 示例函数:skipAd(), enterPage('同城'), searchVideo('关键词'), recognizeVideo()。
  • 决策器 (decider):在前处理数据基础上,用规则生成 actions 列表。
    • 规则用 JSON 配置:支持条件 (if author == 'xxx' then like)、概率 (random 30% then comment)、序列 (after comment then 50% like)。
  • 原子动作 (atomicActions):独立的函数,只执行一次行为,返回 { success: bool, msg: '...' }。
    • e.g., likeVideo(), commentVideo('内容'), replyToComment('回复')。
  • 主要执行器 (mainExecutor):接收 actions 列表,按序执行,返回结果数组。
  • 配置对象 (taskConfig):JSON 驱动整个任务,定义管道、规则等。

2. 示例配置 JSON

每个任务一个 config 对象(可从文件/数据库加载):
{
  "taskName": "搜索视频后概率点赞+评论",
  "prePipeline": [
    "skipAd",              // 函数名或引用
    "enterPage:sameCity",  // 支持参数
    "searchVideo:门窗广告", // 支持参数
    "recognizeVideo"       // 预识别作者/标题
  ],
  "decisionRules": [
    {
      "if": "video.author.includes('品牌X')",  // 条件 (JS 表达式)
      "then": [
        { "action": "likeVideo", "prob": 0.8 },  // 80% 概率点赞
        { "action": "commentVideo", "prob": 0.5, "args": "好产品!" },  // 50% 概率评论
        { "after": "commentVideo", "action": "likeComment", "prob": 0.3 }  // 评论后 30% 概率点赞评论
      ]
    },
    {
      "if": "true",  // 默认规则
      "then": [{ "action": "likeVideo", "prob": 0.3 }]  // 低概率默认点赞
    }
  ],
  "postPipeline": []  // 可选后处理,如“返回推荐页”
}

3. 核心代码实现(Auto.js / JS 示例)

假设你的群控系统用 JS,这里给一个简化版实现(可直接复制到你的脚本)。
// ==================== 原子动作函数(保持纯净,只执行一次) ====================
function skipAd() {
    // 模拟:点击跳过广告
    if (id("skip_ad").exists()) {
        id("skip_ad").findOne().click();
        return { success: true, data: {} };
    }
    return { success: false, msg: "无广告" };
}

function enterPage(pageType) {
    // 模拟:进入同城/搜索页
    if (pageType === 'sameCity') {
        id("same_city_btn").click();
    } // ... 其他类型
    sleep(1000);
    return { success: true, data: { page: pageType } };
}

function searchVideo(keyword) {
    // 模拟:输入搜索 + 确认
    id("search_input").setText(keyword);
    id("search_btn").click();
    sleep(2000);
    return { success: true, data: { keyword } };
}

function recognizeVideo() {
    // 模拟:OCR 或 UI 识别作者/标题
    const author = textContains("@").findOne()?.text() || "";
    const title = descContains("视频标题").findOne()?.desc() || "";
    return { success: true, data: { author, title } };
}

function likeVideo() {
    // 只点赞一次
    if (id("like_btn").exists()) {
        id("like_btn").findOne().click();
        return { success: true, msg: "点赞成功" };
    }
    return { success: false, msg: "点赞失败" };
}

function commentVideo(content) {
    // 只评论一次
    id("comment_input").setText(content);
    id("send_comment").click();
    return { success: true, msg: "评论成功" };
}

function likeComment() {
    // 只点赞最新评论
    if (className("CommentLikeBtn").exists()) {
        className("CommentLikeBtn").findOne().click();
        return { success: true, msg: "点赞评论成功" };
    }
    return { success: false, msg: "无评论可点赞" };
}

// ==================== 函数映射(易扩展) ====================
const funcMap = {
    skipAd, enterPage, searchVideo, recognizeVideo,
    likeVideo, commentVideo, likeComment
    // 加新函数在这里
};

// ==================== 决策器(生成 actions 列表) ====================
function decideActions(videoInfo, rules) {
    const actions = [];
    for (let rule of rules) {
        if (eval(rule.if)) {  // 安全起见,可用 new Function() 代替 eval
            for (let act of rule.then) {
                if (Math.random() < (act.prob || 1)) {
                    actions.push(act);
                }
            }
            break;  // 第一匹配规则生效
        }
    }
    return actions;  // e.g., [{action: "likeVideo"}, {action: "commentVideo", args: "..."}]
}

// ==================== 主要执行器 ====================
function runMain(actions) {
    const results = [];
    let lastAction = null;
    for (let act of actions) {
        // 处理 "after" 依赖
        if (act.after && act.after !== lastAction?.action) continue;

        const func = funcMap[act.action];
        if (func) {
            const res = func(act.args);
            results.push({ action: act.action, ...res });
            lastAction = act;
        } else {
            results.push({ action: act.action, success: false, msg: "未知动作" });
        }
    }
    return results;
}

// ==================== 完整任务运行器 ====================
function runTask(taskConfig) {
    const preResults = [];
    let preData = {};

    // 执行前处理管道
    for (let preStep of taskConfig.prePipeline) {
        const [funcName, arg] = preStep.split(':');  // 支持参数
        const func = funcMap[funcName];
        if (!func) return { success: false, msg: `未知前处理: ${funcName}` };

        const res = func(arg?.trim());
        preResults.push({ step: funcName, ...res });
        if (!res.success) return { success: false, preResults };

        Object.assign(preData, res.data);  // 累积数据
    }

    // 决策生成 actions
    const actions = decideActions(preData, taskConfig.decisionRules);

    // 执行主要脚本
    const mainResults = runMain(actions);

    // 可选后处理(类似前处理)

    return { success: true, preResults, mainResults };
}

// ==================== 示例调用 ====================
const config = { /* 上面的 JSON 示例 */ };
const fullResult = runTask(config);
toastLog(JSON.stringify(fullResult, null, 2));  // 返回整个结果

如何解决你的具体问题

  • 概率点赞/评论:全在前处理决策器里用 prob 处理,主要脚本不变。
  • 评论后概率点赞:用 after: "commentVideo" 在规则里定义依赖顺序,主要脚本无需知道。
  • 给评论评论:加新原子动作 replyToComment(),在规则里加 {action: "replyToComment", after: "commentVideo"}
  • 每种情况不用新前处理:所有任务共享同一管道和决策器,只改 config JSON(e.g., 不同任务有不同 rules)。
  • 群控扩展:在群控主控端,用 JSON config 发给每个设备,设备运行 runTask(config) 返回结果。
这个架构在实际群控系统(如抖音批量脚本)中超稳,代码量少、复用高。如果你需要更细的 Auto.js UI 适配或完整项目 demo,直接说!

© Dominic Hodpel 2022 - 2026