【python】QQ虎年春节活动ADB自动助手项目开发过程(opencv,ADB)(自动开星星,自动红包雨下拉,自动团圆饭,自动一笔连)


QQ虎年春节活动ADB自动助手(自动开星星,自动红包雨下拉,自动团圆饭,自动一笔连)

项目地址:GITHUB QQ虎年春节活动ADB助手
可以进去瞧瞧,顺便别忘了:即便是登录也要给我的博客点个赞啊喂!∫tv‖点赞‖

程序及代码背景介绍

运行环境

  • 语言环境:python3.6
  • 应用的库:opencv-python,numpy,matplotlib等

设计思路

  • 合成团圆饭程序采用ADB库进行操作,外加可选策略的机械式点击组成。
  • 星星一笔连程序利用ADB库进行图像采集,经过opencv识别点与线,并转换为图的形式,再利用dfs进行搜索,最终经过ADB操作输出。

个人代码格式规范约定

  • 函数输入变量统一以In_做前缀
  • 运行中的临时储存变量统一以tmp_为前缀
  • 字典数据统一以DICT_为前缀

本篇随笔中出现的特殊名词

  • 元素:代指合成团圆饭中的不同大小的那个饭
  • 星星:代指整个活动的那个福星
  • 节点:代指一笔连那个活动中的每一个星星图案的节点
  • 连线:代指一笔连那个活动中的每两个星星图案节点间的连线

工程具体开发与实现过程(博客还未写完,可以直接看github)

1.最先写出来的文件————ADB基础操作库:ADB_Basic.py

为了方便具体操作,同时也没有找到网上现成的ADB于python中的操作库,于是自己造轮子写了一个库。。。
首先,便于测试,写了一个利用管道符可以输出cmd返回文本的一个函数,代码如下:

def Command(In_command):  # 支持返回的command执行
    tmp_r = os.popen(In_command)
    tmp_text = tmp_r.read()
    tmp_r.close()
    return tmp_text

然后,便照着ADB的基础操作命令写了其设备显示、点击、滑动、截图及拉取函数
其中,模拟按键的键值对应字典数据如下:

DICT_KEYCODE = {"KEYCODE_UNKNOWN": 0, "KEYCODE_MENU": 1, "KEYCODE_SOFT_RIGHT": 2, "KEYCODE_HOME": 3, "KEYCODE_BACK": 4, "KEYCODE_CALL": 5, "KEYCODE_ENDCALL": 6, "KEYCODE_0": 7, "KEYCODE_1": 8, "KEYCODE_2": 9, "KEYCODE_3": 10, "KEYCODE_4": 11, "KEYCODE_5": 12, "KEYCODE_6": 13, "KEYCODE_7": 14, "KEYCODE_8": 15, "KEYCODE_9": 16, "KEYCODE_STAR": 17, "KEYCODE_POUND": 18, "KEYCODE_DPAD_UP": 19, "KEYCODE_DPAD_DOWN": 20,
 "KEYCODE_DPAD_LEFT": 21, "KEYCODE_DPAD_RIGHT": 22, "KEYCODE_DPAD_CENTER": 23, "KEYCODE_VOLUME_UP": 24, "KEYCODE_VOLUME_DOWN": 25, "KEYCODE_POWER": 26, "KEYCODE_CAMERA": 27, "KEYCODE_CLEAR": 28, "KEYCODE_A": 29, "KEYCODE_B": 30, "KEYCODE_C": 31, "KEYCODE_D": 32, "KEYCODE_E": 33, "KEYCODE_F": 34, "KEYCODE_G": 35, "KEYCODE_H": 36, "KEYCODE_I": 37, "KEYCODE_J": 38, "KEYCODE_K": 39, "KEYCODE_L": 40,
 "KEYCODE_M": 41, "KEYCODE_N": 42, "KEYCODE_O": 43, "KEYCODE_P": 44,"KEYCODE_Q": 45, "KEYCODE_R": 46, "KEYCODE_S": 47, "KEYCODE_T": 48, "KEYCODE_U": 49, "KEYCODE_V": 50, "KEYCODE_W": 51, "KEYCODE_X": 52, "KEYCODE_Y": 53, "KEYCODE_Z": 54, "KEYCODE_COMMA": 55, "KEYCODE_PERIOD": 56, "KEYCODE_ALT_LEFT": 57, "KEYCODE_ALT_RIGHT": 58, "KEYCODE_SHIFT_LEFT": 59, "KEYCODE_SHIFT_RIGHT": 60,
 "KEYCODE_TAB": 61, "KEYCODE_SPACE": 62, "KEYCODE_SYM": 63, "KEYCODE_EXPLORER": 64, "KEYCODE_ENVELOPE": 65, "KEYCODE_ENTER": 66, "KEYCODE_DEL": 67, "KEYCODE_GRAVE": 68, "KEYCODE_MINUS": 69, "KEYCODE_EQUALS": 70, "KEYCODE_LEFT_BRACKET": 71, "KEYCODE_RIGHT_BRACKET": 72, "KEYCODE_BACKSLASH": 73, "KEYCODE_SEMICOLON": 74, "KEYCODE_APOSTROPHE": 75, "KEYCODE_SLASH": 76, "KEYCODE_AT": 77, "KEYCODE_NUM": 78, "KEYCODE_HEADSETHOOK": 79, "KEYCODE_FOCUS": 80,
 "KEYCODE_PLUS": 81, "KEYCODE_MENU": 82, "KEYCODE_NOTIFICATION": 83, "KEYCODE_SEARCH": 84, "TAG_LAST_KEYCODE": 85}

以及相应的ADB操作函数:

def ADB_screen_size():
    '获取手机屏幕大小'
    size_str = Command('adb shell wm size')
    m = re.search(r'(\d+)x(\d+)', size_str)
    if m:
        return (m.group(2), m.group(1))
    return (0,0)

def ADB_devices_re():  # 显示ADBdevices(非列表)re后缀为有返回值
    return Command("adb devices")


def ADB_tap(In_x: int, In_y: int):  # 模拟点击操作 无返回值
    os.system("adb shell input tap "+str(In_x)+" "+str(In_y))


def ADB_key(In_keycode: int):  # 模拟按键
    os.system("adb shell input keyevent "+str(In_keycode))


def ADB_swipe(In_startX: int, In_startY: int, In_endX: int, In_endY: int, In_timems: int):  # 模拟滑动
    os.system("adb shell input swipe "+str(In_startX)+" " +
              str(In_startY)+" "+str(In_endX)+" "+str(In_endY)+" "+str(In_timems))

同时,当时为了兼顾可能的调试,还写了最终版暂时没有用到的代码部分:

from Output_Basic import *  # 本操作可注释掉 (不需要显示的话,以下均可注释)
import threading
# 本函数可注释掉
def ADB_tap_re(In_x: int, In_y: int):  # 模拟点击操作 re为有返回值
    return Command("adb shell input tap "+str(In_x)+" "+str(In_y))

# 本函数可注释掉
def ADB_key_re(In_keycode: int):  # 模拟按键
    return Command("adb shell input keyevent "+str(In_keycode))

# 本函数可注释掉
def ADB_swipe_re(In_startX: int, In_startY: int, In_endX: int, In_endY: int, In_timems: int):  # 模拟滑动
    return Command("adb shell input swipe "+str(In_startX)+" " +
                   str(In_startY)+" "+str(In_endX)+" "+str(In_endY)+" "+str(In_timems))

# 本函数可注释掉
def ADB_text(In_text: str):  # 发送文本
    return Command("adb shell input "+In_text)

# 本函数可注释掉
TMP_flash = False  # 是否刷新
def Img_cv2_monitor(In_imgpath: str, In_delayms: int = 1000, In_Windowtitle: str = "ADB_Img"):  # 必须已经有图像进行初始化
    cv2.namedWindow(In_Windowtitle, 0)  # 此处有别于使用Output库的方式(因为需要持续输出显示)
    global TMP_flash
    try:
        while True:
            if TMP_flash:
                img = cv2.imread(In_imgpath)
                cv2.imshow(In_Windowtitle, img)
                TMP_flash = False
            cv2.waitKey(In_delayms)
    except KeyboardInterrupt:
        return "Stop Now..."

# 本函数可注释掉
def ADB_screen_show(In_phonepath: str = "/sdcard/ADB01.png", In_pcpath: str = "D:\\ADB01.png"):  # 显示屏幕
    Command("adb shell screencap -p "+In_phonepath)
    tmp = Command("adb pull \""+In_phonepath+"\" \""+In_pcpath+"\"")
    Out_img_cv2(In_pcpath)
    return tmp


# 本函数可注释掉
# 监视屏幕,因长时间显示图片,所以用了threading+opencv显示,但是还是速度一般。。希望有大佬指教
def ADB_screen_monitor(In_phonepath: str = "/sdcard/ADB01.png", In_pcpath: str = "D:\\ADB01.png", In_delayms: int = 1000):
    tmp_cv2 = threading.Thread(
        target=Img_cv2_monitor, args=(In_pcpath, In_delayms))
    tmp_cv2.start()
    global TMP_flash
    try:
        while True:
            if TMP_flash == False:
                Command("adb shell screencap -p "+In_phonepath)
                Command("adb pull \""+In_phonepath+"\" \""+In_pcpath+"\"")
                TMP_flash = True
                time.sleep(In_delayms/1000)
    except KeyboardInterrupt:
        return "Stop Now..."

还有网上花了好大力气才找到的一个按下、移动、抬起的命令,在这里分享一下(但是不知道轨迹球这个输入模式在现在手机还能不能用):
input trackball press这个命令是模拟轨迹球发送点击命令
input trackball roll这个命令是模拟轨迹球发送滚动命令
那位朋友说的是:因为现在手机设备上没有轨迹球,然并卵…(当然你自己可以测试测试)
同时分享一个小技巧:长按就是一种特殊的滑动,即位置不变的滑动哦!
adb shell input swipe 100 100 100 100 1000 //在 100 100 位置长按 1000毫秒

Cnblogs
CSDN Android adb input 命令介绍

2.其次写出来的文件————Output基础显示库:Output_Basic.py

屏幕显示的流程无非就一种:adb手机截屏——>adb拉取图片——>调用显示库显示
而显示库中图片的显示也无非就三种途径:
matplotlib库显示,利用matplotlib打开,里面有坐标显示,比较方便

def Out_img_plt(In_imgpath: str):  # 利用matplotlib打开,里面有坐标显示,比较方便
    tmp_Img = mpimg.imread(In_imgpath)
    plt.imshow(tmp_Img)  # 显示图片
    plt.axis('off')  # 不显示坐标轴
    plt.show()

opencv库显示,利用opencv-python打开,打开速度更快,比较迅速,同时也便于直接同一个窗口更换图片

def Out_img_cv2(In_imgpath):  # 利用opencv-python打开,打开速度更快,比较迅速
    start = time.clock()
    img = cv2.imread(In_imgpath)
    cv2.namedWindow("ADB_Img", 0) # 0代表opencv窗口大小可变
    cv2.imshow('ADB_Img', img)
    elapsed = (time.clock() - start)
    key = cv2.waitKey(0)
    return elapsed

通过PIL直接调用系统默认图片显示软件,单张图片的话一般相对更快一些,但没有坐标显示和等待操作

def Out_img_PIL(In_imgpath):  # 直接系统默认程序打开图片
    im = Image.open(In_imgpath)
    im.show()

其中,为了方便计时比较,可以用到下面的计时修饰器,同时整个output文件的调用库如下:

import cv2
import time
from functools import wraps
import matplotlib.pyplot as plt  # plt 用于显示图片
import matplotlib.image as mpimg  # mpimg 用于读取图片
from PIL import Image
def timethis(func):  # 函数计时修饰器,成品暂未用上 用法在要计时的函数def的前一行添加"@timethis"
    @wraps(func)
    def wrapper(*args, **kwargs):
        start = time.perf_counter()
        r = func(*args, **kwargs)
        end = time.perf_counter()
        print('{}.{} : {}ms'.format(func.__module__,
                                    func.__name__, (end - start)*1000))
        return r
    return wrapper

修饰器用法例如:

@timethis
def functionA():
    ………………

functionA() # 此时将会运行函数的同时将函数运行时间输出在屏幕上

3.后来写出来的文件————Apply应用接口库:ADB_Apply.py

其中有三种应用接口:
自动团圆饭
因为截图有太长耗时的缘故,并且这个AI也不好设计,所以直接把这个团圆饭助手写成机械式操作了(分为三种操作模式:两侧放置、中央放置、左侧放置)。
但是同时竟然还稍微有可以利用碰撞分离不同大小元素的效果。
而且极力推荐中央放置,这样比较均匀一点,很少出现一边直接撞破红线游戏结束,同时分离效果还好一点。
(在下也就用这个脚本运气好打了个4093分,好友排行第一∫tv‖微笑‖)

def App_synthesis(In_X: int, In_Y: int):
    while True:
        try:
            tmp_random1 = randint(int(-In_Y/8), int(In_Y/8))
            tmp_in = int(input(u"请选择您的模式编号: (1=两侧放置, 2=中央放置, 3=左侧放置): "))
            print(u"【系统】循环点击正在运行中,如要终止请按 Ctrl+C")
            if(tmp_in == 1):
                while True:
                    ADB_tap(10, In_Y/2 + tmp_random1)  # 左边界处按一下
                    time.sleep(0.15)
                    ADB_tap(In_X-20, In_Y/2 + tmp_random1)  # 右边界处按一下
                    time.sleep(0.15)
            elif(tmp_in == 2):
                ADB_tap(In_X/2+5, In_Y/4 + tmp_random1)  # 中央处按一下
                time.sleep(0.15)
                while True:
                    ADB_tap(In_X/2, In_Y/4 + tmp_random1)  # 中央处按一下
                    time.sleep(0.15)
            elif(tmp_in == 3):
                while True:
                    ADB_tap(10, In_Y/2 + tmp_random1)  # 左边界处按一下
                    time.sleep(0.15)
        except KeyboardInterrupt:
            print(u"【等待】循环已执行停止,如要继续开始请按任意键(Esc键退出)...")
        if msvcrt.getch() == b'\x1b':  # 操作获取Esc
            return

自动红包雨下拉,目前速度依然较慢,希望能有大佬指点,让ADB变快(不加等待时间ADB直接罢工。。。)

def App_pull(In_X: int, In_Y: int):
    while True:  # 流星雨下拉(目前速度依然较慢。。)
        try:
            print(u"【系统】循环下拉正在运行中,如要终止请按 Ctrl+C")
            while True:  # 流星雨下拉(目前速度依然较慢。。)
                ADB_swipe(In_X/2, In_Y/4, In_X/2, In_Y/4*3, 100)
                time.sleep(0.1) # 不加等待时间ADB直接罢工。。。
                # print(u"...")
        except KeyboardInterrupt:
            print(u"【等待】循环已停止,如要继续下拉请按任意键(Esc键退出)...")
            if msvcrt.getch() == b'\x1b':  # 操作获取Esc
                return

自动开星星,可以指定次数开启

def App_open(In_X: int, In_Y: int):
    while True:
        tmp_in = int(input(u"请输入您要打开的次数: "))
        print(u"【系统】循环点击正在运行中,如要终止请按 Ctrl+C")
        try:
            for i in range(tmp_in):
                ADB_tap(In_X/2, In_Y/2)
                time.sleep(2)
                ADB_key(DICT_KEYCODE["KEYCODE_BACK"])
                time.sleep(0.5)
        except KeyboardInterrupt:
            print(u"【终止】循环已强制停止")
        print(u"【等待】循环已执行停止,如要继续开始请按任意键(Esc键退出)...")
        if msvcrt.getch() == b'\x1b':  # 操作获取Esc
            return
    # 自动开星星

4.最后在好友@fmq03Github的构思与主力下写成的一笔连代码(与前三者关联较少,可以直接看这个)

用到的知识:dfs,欧拉路,霍夫圆
参考文档:

首先定义节点这一类,便于储存点的坐标及关联

class _pos:  # 定义的点的信息,遍历寻路用

    def __init__(self, circle_x, circle_y, key):
        self.id = key  # 该点的id
        self.posx = circle_x  # 圆心坐标
        self.posy = circle_y
        self.To = []  # 可到达圆心的id集合
        self.numTo = 0
        self.isvisit = False

        return

    def addTo(self, keyto):
        self.numTo += 1
        self.To.append(keyto)
        return

其次,创建整个分析的主类:
其主要调用流程就是:

  • 先读取图片并做简单处理(转灰度、取指定色彩范围内的图像
  • 再利用灰度图利用霍夫圆寻找节点与其半径
  • 接着用穷举法扫描出其中每两个节点之间是否存在连线

扫描方法即为利用刚刚色彩范围分离出来的图像,在两点之间取采样点,并判断颜色是否匹配

  • 最后将点的存储转换为两点间矩阵数据,利用dfs进行扫描
class _analyze:  # 主要类

    def __init__(self, xpath):
        self.path = xpath
        self.posnum = 0
        self.graph = []
        self.table = []  # 创建了表
        self.routine = []  # DFS栈
        self.be_id = 0
        return

    def check_new(self, In_y1: float, In_x1: float, In_y2: float, In_x2: float, In_R: float):#检查两点间是否存在连线
        tmp_distance = math.sqrt((In_x1-In_x2) * (In_x1-In_x2) +
                                 (In_y1-In_y2) * (In_y1-In_y2))  # 根据距离切分点
        m = 0
        # print(In_R, In_x1, In_y1, In_x2, In_y2)
        tmp_dx = (In_x2-In_x1)/tmp_distance
        tmp_dy = (In_y2-In_y1)/tmp_distance
        tmp_sx = In_x1+tmp_dx*In_R
        tmp_sy = In_y1+tmp_dy*In_R
        # print(tmp_dx, tmp_dy, tmp_sx, tmp_sy)
        for i in range(int(tmp_distance-2*In_R)):
            tx = int(tmp_sx+tmp_dx*i)
            ty = int(tmp_sy+tmp_dy*i)
            # print(tx,ty,self.res[tx,ty])
            if self.res[tx, ty] > 0:
                # cv2.circle(self.img, (ty, tx), 2, (255, 0, 255), 10)
                m += 1
        # print('result:'+str(m/(tmp_distance-2*In_R)))
        if m/(tmp_distance-2*In_R) > 0.93:
            # print("---------Find one!---------\n")
            return True
        else:
            # print('---------------------------\n')
            return False

    def load(self):  # 主要处理函数
        self.img = cv2.imread(self.path)  # 读取图像
        gray = cv2.cvtColor(self.img, cv2.COLOR_BGR2GRAY)  # 转灰度图用于圆检测
        rgb = cv2.cvtColor(self.img, cv2.COLOR_BGR2RGB)  # 转hsv图用于颜色提取

        # 霍夫圆查找圆
        circles1 = cv2.HoughCircles(
            gray, cv2.HOUGH_GRADIENT, 1, 60, param1=100, param2=30, minRadius=50, maxRadius=80)
        circles = circles1[0, :, :]
        circles = np.uint16(np.around(circles))
        for i in circles:  # 遍历每个圆心
            if i[1] < lowy or i[1] > highy:  # 不符合边界要求,删去
                continue
            # cv2.circle(self.img, (i[0], i[1]), i[2],
            #            (255, 255, 0), 5)  # 画出每个圆心和半径
            # cv2.circle(self.img, (i[0], i[1]), 2, (255, 0, 255), 10)
            vi = _pos(i[0], i[1], self.posnum)  # 记录到graph(pos集合)中
            radio = i[2] + 6
            self.graph.append(vi)
            self.posnum += 1
        # print(circles)
        # 提取颜色蒙版
        colorLow = np.array([20, 10, 20])  # rgb颜色边界
        colorHigh = np.array([140, 120, 115])
        mask = cv2.inRange(rgb, colorLow, colorHigh)  # 提取颜色区域
        self.res = mask  # 与原图位运算

        oddid = 0
        self.table = np.zeros((self.posnum, self.posnum))
        for vi in self.graph:  # 两两遍历顶点,判断是否有边
            for vj in self.graph:
                if vi.id == vj.id or vi.id in vj.To or vj.id in vi.To:
                    continue
                # print(vi.id, "<--->", vj.id)
                if self.check_new(float(vi.posx), float(vi.posy), float(vj.posx), float(vj.posy), float(radio)):
                    vi.addTo(vj.id)
                    vj.addTo(vi.id)
                    self.table[vi.id][vj.id] = 1
                    self.table[vj.id][vi.id] = 1
                    # cv2.line(self.img, (vi.posx, vi.posy),
                    #          (vj.posx, vj.posy), (255, 0, 0), 10)  # 若有边,画出这条线
        for vi in self.graph:
            if vi.numTo % 2 == 1:
                oddid = vi.id
            # cv2.putText(self.img, str(vi.id), (vi.posx, vi.posy),
            #             cv2.FONT_HERSHEY_COMPLEX, 2.0, (0, 0, 255), 5)
        # print(oddid)
        # print(ana.table)
        self.be_id = oddid
        # cv2.circle(self.img, (self.graph[oddid].posx,
        #   self.graph[oddid].posy), 20, (255, 0, 255), 10,)

        # plt.subplot('121')
        # plt.imshow(self.img[:, :, [2, 1, 0]])
        # plt.subplot('122')
        # plt.imshow(self.res[:, :])
        # # print(radio)
        # plt.show()
        # plt.xticks([]),plt.yticks([])
        # plt.show()

    def dfs(self, j):
        for i in range(self.posnum):  # 挨个寻找与 t 连接的边
            if self.table[i][j] or self.table[j][i]:  # 如果这里有边,while 防止多边连接两点相同
                self.table[i][j] -= 1  # 该边数量减一,代表该边走过了
                self.table[j][i] -= 1  # 无向图
                self.dfs(i)
        self.routine.append(j)  # 回溯时把 t 点放进栈里1

写成的整体调用接口如下:

def Apply_draw(IN_tmpdir_with_splash: str = get_desktop()+"\\"):
    while True:
        print(u"【系统】循环点击正在运行中,如要终止请按 Ctrl+C")
        try:
            while True:
                Command("adb shell screencap -p /sdcard/ADB01.png")
                Command("adb pull /sdcard/ADB01.png \"" +
                        IN_tmpdir_with_splash+"ADB01.png\"")
                # 读取图像
                ana = _analyze("\""+IN_tmpdir_with_splash+"ADB01.png\"")
                ana.load()
                ana.dfs(ana.be_id)
                print("【系统】连接顺序: ",ana.routine)
                for i in range(len(ana.routine)-1):
                    # print(ana.graph[ana.routine[i]].id, "-->", ana.graph[ana.routine[i+1]].id, ana.graph[ana.routine[i]].posx, ana.graph[ana.routine[i]].posy,
                    #   ana.graph[ana.routine[i+1]].posx, ana.graph[ana.routine[i+1]].posy)
                    ADB_swipe(ana.graph[ana.routine[i]].posx, ana.graph[ana.routine[i]].posy,
                            ana.graph[ana.routine[i+1]].posx, ana.graph[ana.routine[i+1]].posy, 200)
                    time.sleep(0.15)
                time.sleep(2)
        except KeyboardInterrupt:
            print(u"【终止】循环已强制停止")
        print(u"【等待】循环已执行停止,如要继续开始请按任意键(Esc键退出)...")
        if msvcrt.getch() == b'\x1b':  # 操作获取Esc
            return

最后最后的主文件(写成匹配性强的)————>ADB_Main.py

一个调用内部在下写的库(Apply, Basic)的外接入口,(输入操作已写好)直接运行即可
详情内容请参见github
项目地址:GITHUB QQ虎年春节活动ADB助手
可以进去瞧瞧,顺便别忘了:即便是登录也要给我的博客点个赞啊喂!∫tv‖点赞‖

github中的README文档

  • 自动团圆饭:本ADB助手采用了简易的策略,主要是对屏幕进行机械式点击操作 (没有AI) ,这样可以均衡并且利用碰撞原理分离大小不同的“饭”(1=两侧放置, 2=中央放置, 3=左侧放置)
  • 自动一笔连:采用图像识别 + dfs的欧拉路取路径操作,并自动点击连线

文件名及内容:

  • ADB_Main.py: 一个调用内部在下写的库(Apply, Basic)的外接入口,(输入操作已写好)直接运行即可
  • ADB_Apply.py: 在下根据ADB主库外加的相关操作接口,可以实现相关的腾讯春节应用操作
  • ADB_Apply_draw.py: 由 @fmq03 开发(感谢大佬!),在下辅助的根据ADB主库外加的相关操作接口,可以实现相关的一笔连操作
  • ADB_Basic.py: 在下自己封装的ADB主库,具体函数请看内部(不多,就几十行)
  • Output_Basic.py: 利用cv2/PIL/matplotlib的库写的截图显示用的库(函数都封装好了,ADB_Basic.py调用上了)

配置及运行方法:

  • 请安装好ADB、python并全部配置好环境变量
  • 安装所有需要的库文件“pip install ”+库名(opencv-python) (matplotlib,pillow可选,不需要即可直接在Basic.py中注释掉,已经默认注释掉)
  • 打开手机开发者选项(网上百度),并开启USB调试选项
  • 同时在电脑上安装相应品牌的“手机助手”以获取ADB驱动(实践中,安装之后在ADB中能连上手机了,手机管家/助手软件也就可以卸载了)
  • 打开春节相关活动界面,并尽量保持初始化的状态不要手动操作,运行“ADB_Main.py”中的相关操作,开始享受吧!

Tips:

  • 运行过程中,如果手机运行较卡或丢失操作,可以手动设置延长操作时间(查找及修改方法不再赘述)

免责声明:

  1. 本程序仅供学习与交流用途,且仅模拟人的机械性重复操作,减少无聊的机械性操作,未修改腾讯软件、客户端相应代码。
  2. 非盈利谨慎使用,保护QQ,珍惜腾讯!!!造成的一切处理和后果与开发者本人无关,切勿沉迷及滥用,请在下载之后24小时内务必删除。