汽水music自动看广告领取VIP

起因是我在小黄鱼闲逛,看到有人卖 汽水music 自动刷 VIP 的软件,我是汽水音乐的用户啊,既然他们都能卖这样的软件,那我是不是也可以自己写一个;研究了一通,于是就有了这篇文章。

汽水音乐可以靠看广告领VIP时长的,看完一个广告点右上角的"领取成功",弹窗里再点"领取奖励",接着看下一个。整个过程就是重复地看和点。

📌 脚本做的事情:用 ADB 截手机屏幕,用 RapidOCR 识别屏幕上的文字,认到"领取奖励""领取成功"就模拟点击。脚本不改 app 也不调接口,做的事和手动点一样。换掉关键词,同样的思路也能用在别的看广告领奖励的 app 上。只想直接用的,跳到最后一节"使用方法"。

源码:github.com/webxin666/q...

实际跑起来的效果

我用 Android 手机连 Mac 跑了两轮,共点击 34 次,每次点击都留了带标注的截图。

从截图的时间戳能看出节奏:

  • 从点"领取奖励"进入广告,到右上角出现"领取成功"并被点掉,15 次里有 14 次在 22~26 秒之间,另有一次隔了 3 分 38 秒
  • 点完"领取成功"弹出奖励弹窗,到点"领取奖励",间隔 1~2 秒
  • 15:01:19 到 15:05:29 之间连续点了 11 次"领取奖励",平均 25 秒一轮

按这个速度挂一小时大约能看 144 个广告(估,3600 ÷ 25)。每个广告能换多少时长看 app 的规则,弹窗里写的是"再看 N 个视频提前得第 X 日免费听",我没有统计。

整体思路

广告页的流程是固定的:

广告播放 → 右上角出现"领取成功" → 点它,弹出奖励弹窗 → 点"领取奖励" → 下一个广告

所以脚本就是一个死循环:

截图 → OCR 识别文字 → 匹配目标词 → 检查位置 → 点击 → 等一会儿,回到截图

用到的东西:

环节 用的工具
截图、点击 ADB(screencap、input tap)
认字 rapidocr-onnxruntime 1.4.4(PaddleOCR 模型的 ONNX 版本)
图片处理 opencv-python、numpy

用 OCR 定位,不写死坐标

最省事的写法是写死坐标,固定点某个位置。但看一下这 34 次点击的实际坐标(手机分辨率 1080×2400):

按钮 x 范围 y 范围
领取成功 851~926 152153 或 261265
领取奖励 538~542 1310~1388

"领取成功"的纵坐标有两档,相差 100 多像素,是不同广告的布局不一样。"领取奖励"的上下位置也有将近 80 像素的浮动。写死坐标的话,换个广告就点空了,换台手机更是要重新量。

OCR 的好处是只认字。按钮挪到哪都能找到,换手机也不用改代码。代价是 app 改了按钮文案就得跟着改配置。

几处关键实现

截图:用 exec-out 直接拿 PNG

python 复制代码
def screenshot():
    try:
        result = subprocess.run(["adb", "exec-out", "screencap", "-p"], capture_output=True, timeout=ADB_TIMEOUT)
    except subprocess.TimeoutExpired:
        return None
    if result.returncode != 0 or not result.stdout:
        return None
    img = cv2.imdecode(np.frombuffer(result.stdout, np.uint8), cv2.IMREAD_COLOR)
    return img

adb exec-out 把 PNG 的二进制直接输出到 stdout,在内存里解码,不用先存到手机再 pull 下来。用 exec-out 而不是 adb shell,是因为 shell 会分配终端,二进制数据可能被换行符转换弄坏。

所有 adb 调用都加了 10 秒超时。手机断开或者 adb 卡住时,脚本不会一直挂着。

OCR:先缩图,跳过方向分类

python 复制代码
def run_ocr(screen):
    h, w = screen.shape[:2]
    scale = 1.0
    img = screen
    if w > OCR_MAX_WIDTH:
        scale = OCR_MAX_WIDTH / float(w)
        img = cv2.resize(screen, (int(w * scale), int(h * scale)), interpolation=cv2.INTER_AREA)

    # 屏幕文字都是正向的,跳过方向分类以提速
    result, _ = get_ocr()(img, use_cls=False)
    ...

RapidOCR 安装包里自带三个模型:检测文字区域的 PP-OCRv4 det(4.7 MB),识别文字的 PP-OCRv4 rec(10.9 MB),判断文字方向的 cls(0.6 MB)。手机屏幕上的字都是正的,所以用 use_cls=False 关掉方向判断。

截图先缩到 720 宽再识别,坐标最后再按比例还原回去。我在 M3 Pro 上用 10 张截图测了一下,缩图后单帧平均 0.49 秒,原图平均 0.61 秒,快了两成左右,不算多。

文字匹配:包含即可,允许错一个字

OCR 识别出来的文字经常带点别的东西。实际碰到过这两种:

  • 有的广告右上角是"24s | 领取成功 ×",倒计时和按钮被识别成了一整段"24s|领取成功"
  • 叉号被粘在文字后面,识别成"领取成功×"

所以匹配时先清洗掉首尾的符号,再判断识别结果里有没有完整包含目标词。认错一个字也算命中:

python 复制代码
def text_match(recognized: str, target: str) -> bool:
    a = normalize_text(recognized)
    b = normalize_text(target)
    if not a:
        return False
    # 只认「识别结果里包含完整目标词」;反过来不行,否则单个「取」「成」也会命中
    if b in a:
        return True
    if not FUZZY or len(a) < len(b):
        return False
    # 允许错 1 个字:在识别结果上滑动一个目标词长度的窗口,逐字按位置比对
    n = len(b)
    for i in range(len(a) - n + 1):
        if sum(x == y for x, y in zip(a[i:i + n], b)) >= n - 1:
            return True
    return False

需要注意包含关系的方向:只能是识别结果包含目标词,反过来不行。否则 OCR 单独认出一个"取"字,也会被当成"领取奖励"。

点击区域和优先级

光认字还不够,为了不误点画面其他位置出现的同名文字,每个目标词都限定了可点击的区域:

python 复制代码
TARGET_ROI = {
    "领取奖励": {"x": (0.25, 0.75), "y": (0.35, 0.70)},  # 中央
    "继续观看": {"x": (0.25, 0.75), "y": (0.35, 0.70)},  # 中央
    "领取成功": {"x": (0.0, 1.0), "y": (0.01, 0.97)},    # 几乎全屏(含右上)
}

弹窗按钮必须在屏幕中间,区域外的同名文字直接跳过。"领取成功"的位置不固定,就基本放开到全屏。

TARGETS 的顺序就是优先级,同一帧里先点"领取奖励"。这是必要的,奖励弹窗是盖在广告页上面弹出来的,那一帧里右上角的"领取成功"其实也还在,如果先点它就点错了。

防止对同一个位置反复点击

如果某个按钮点了没反应(比如弹窗没关掉),脚本会一直认到它、一直点。所以加了个限制:同一个词在同一位置 20 秒内点了 4 次还在,就暂停点它 30 秒。

python 复制代码
def should_pause(target, x, y, sw):
    """同一位置最近已点满 REPEAT_LIMIT 次:暂停该目标并返回 True(本次不点)"""
    now = time.time()
    recent_clicks[:] = [c for c in recent_clicks if now - c[0] <= REPEAT_WINDOW]
    tol = REPEAT_TOL * sw
    same = sum(
        1 for _, t, cx, cy in recent_clicks
        if t == target and abs(cx - x) <= tol and abs(cy - y) <= tol
    )
    if same < REPEAT_LIMIT:
        return False
    paused_until[target] = now + REPEAT_PAUSE
    recent_clicks[:] = [c for c in recent_clicks if c[1] != target]
    return True

"同一位置"允许有屏幕宽度 3% 的误差,因为 OCR 每次框出来的中心点会差几个像素。

每次点击留一张标注截图

开启 SAVE_CLICK_DEBUG 后,每次点击都会在 debug_images/ 存一张图:红色十字是点击位置,绿框是允许点击的区域,顶部写着 OCR 原文、置信度和坐标。文件名带时间、目标词和坐标,比如 20261015_150119_0005_领取奖励_541_1370.png。

上面的节奏统计和坐标范围,都是直接从这些文件名里算出来的。排查有没有点错也只能靠它们。

使用方法

1. 安装 Python 依赖

bash 复制代码
# Windows
pip install -r requirements.txt

# Mac
pip3 install -r requirements.txt

2. 手机打开 USB 调试

在"设置 > 开发者选项"里打开"USB 调试",有的手机还要打开"USB 调试(安全设置)"或"允许模拟点击",否则 input tap 点不动。连上数据线,手机上勾选允许调试,然后用 adb devices 确认能看到设备。

3. 运行

手机打开汽水音乐,进到看广告领时长的页面,保持屏幕常亮。

bash 复制代码
# Windows(也可以直接双击仓库里的 windows启动.bat)
python qishui_script.py

# Mac
python3 qishui_script.py

控制台出现"✅ OCR 已就绪"后就开始自动运行了,Ctrl + C 停止。

可调的配置

都在脚本顶部的配置区:

配置项 默认值 说明
TARGETS 领取奖励,继续观看,领取成功 要点的文字,靠前的优先
OCR_SCORE 0.5 置信度低于这个值的结果直接丢掉
FUZZY True 是否允许认错一个字
POLL_INTERVAL 1.2 没找到目标时,隔多少秒再截图
CLICK_COOLDOWN 2.0 点击后等多少秒,"领取成功"例外,点完立刻识别
OCR_MAX_WIDTH 720 截图宽度超过它就先缩小再识别
SAVE_CLICK_DEBUG True 是否保存每次点击的标注截图
REPEAT_WINDOW / REPEAT_LIMIT / REPEAT_PAUSE 20 / 4 / 30 防重复点击:20 秒内同一位置点 4 次就暂停 30 秒

问题

  • 目前只支持 Android,iOS 没有 ADB
  • 测试用的 app 版本是 19.1.1,按钮文案一改就要改 TARGETS

最后

代码只是拿来学习 ADB 和 OCR 自动化,自己用用就好。自动化操作可能违反 app 的用户协议,账号上的风险需要自己承担。

相关推荐
梦里寻码6 小时前
给 AI Agent 搭围栏:Monorepo 是被低估的 Agent 基础设施
前端·后端·github
高晶6 小时前
Android 电子词典开发实战指南
后端·程序员
用户922434277267 小时前
会拍你的番茄钟:我在 Rokid Glasses 上写了一个会「盯」着你的 AIUI 智能体
程序员
高晶7 小时前
Android 计算器开发实战:从界面设计到核心逻辑
程序员·设计
穆梓兰煊7 小时前
Flutter端云协同推理架构解析
flutter·github
高晶7 小时前
ARM 嵌入式 Linux 系统 U-Boot 开发与移植实战M
设计模式·程序员
AaronMan8 小时前
ZIP 压缩包为什么有时多一层目录?——看懂 ZIP 文件名与内部目录的关系
程序员
楠风测开8 小时前
MySQL 基础 + AI SQL 优化
程序员
Sperains8 小时前
换电脑不用重配:WSL 环境的备份、验证与迁移
程序员