最近,微信跳一跳风靡朋友圈,Github上又有大佬用Python写出自动外挂,就因为感兴趣学习了一波还是有点难理解,不过主要还是去了解编程思想的,也算学习一下。下面是主要关键的学习代码(运行不了不完整,想了解的去这里)
主要步骤 微信跳一跳
配置(手机环境ADB) 让电脑去操作手机(ADB)-----只用设置环境变量,分析出棋子棋盘
截图
分析棋子的坐标和棋盘的范围
计算距离
根据距离来在配置文件里按压时间执行---》截图
等待1-2秒
# -*- coding:utf-8 -*-
import time
import random
import os
import json
import subprocess #subprocess通过子进程来执行外部指令,并通过input/output/error管道,获取子进程的执行的返回信息。
import re
from PIL import Image
def get_screen_size():
"""获取手机屏幕分辨率"""
# 1920x1080
size_str = os.popen('adb shell wm size').read() #执行adb shell 命令获取手机分辨率(1920x1080)
if not size_str:
print('请安装adb 及驱动并配置环境变量')
exit()
m = re.search(r'(\d+)x(\d+)', size_str) #用正则表达式匹配和提取 分辨率 字符
if m:
return "%sx%s" % (m.group(2), m.group(1))
def init():
"""初始化,获取配置,检查环境"""
# 获取分辨率
screen_size = get_screen_size()
# 配置文件路径
config_file_path = 'config/%s/config.json' % screen_size #获取相应的分配率配置文件
if os.path.exists(config_file_path):
with open(config_file_path, 'r') as f:
print('Load config file from %s' % config_file_path) #用json模块中的loads转换json
return json.loads(f.read())
else:
with open('config/default.json', 'r') as f:
print('Load default config')
return json.loads(f.read())
def get_screenshot():
"""获取截图"""
"""auto.png"""
process = subprocess.Popen('adb shell screencap -p', shell=True, stdout=subprocess.PIPE)
screenshot = process.stdout.read()
screenshot = screenshot.replace(b'\r\r\n', b'\n')
with open('auto.png', 'wb') as f:
f.write(screenshot)
def find_piece_board(img, config):
"""根据图片和配置文件找到棋盘棋子坐标"""
# 获取图片的宽和高
w, h = img.size
# 扫描起始y坐标
scan_start_y = 0
# 棋子的最大y坐标
piece_y_max = 0
# 图片的像素矩阵
img_pixel = img.load()
# 以50px 为步长 扫描,测试出最高点
for i in range(h//3, h*2//3, 50):
first_pixel = img_pixel[0, i]
for j in range(1, w):
pixel = img_pixel[j, i]
# 如果不是纯色的 跳出,说明找到了y轴的最大值
if first_pixel[:-1] != pixel[:-1]:
scan_start_y = i - 50
break
if scan_start_y:
break
# 开始扫描棋子
left = 0
right = 0
for i in range(scan_start_y, h*2//3):
flag = True
for j in range(w//8, w*7//8): # 切掉左右1/8
pixel = img_pixel[j, i]
# 根据棋子的颜色判断,找到最后一行的点的起始后末尾
if (50 < pixel[0] < 60) and (53 < pixel[1] < 63) and (95 < pixel[2] < 110):
if flag:
left = j
flag = False
right = j
piece_y_max = max(i, piece_y_max)
piece_x = (left+right)//2
piece_y = piece_y_max - config['piece_base_height_1_2']
print(piece_x, piece_y)
def jump(distance, param):
"""跳一段距离"""
pass
def test_piece():
config = init()
img = Image.open('auto.png')
find_piece_board(img, config)
def run():
"""主函数"""
# 获取配置,检查检查环境
config = init()
# print(config)
# 循环操作
while True:
# 获取截图
get_screenshot()
# 生成图片对象
img = Image.open('auto.png')
# 获取棋子, 棋盘坐标
piece_x, piece_y, board_x, board_y = find_piece_board(img, config)
# 计算距离
distance = ((piece_x-board_x)**2 + (piece_y-board_y)**2)**0.5
# 跳
jump(distance, config['press_ratio'])
# 随机间隔时间
time.sleep(1+random.random()*2)
if __name__ == '__main__':
#run()
test_piece()
手动版(可以运行)
# -*- coding: utf-8 -*-
"""
跳一跳手动版(先点起点再点终点)
根据numpy和 matplotlib库来分析棋子和棋盘坐标并显示动态截图,用鼠标点击实现跳跃
"""
import os
import time
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation #刷新手机截图图片(跳之前和其后的截图,动态的)
from PIL import Image
def pull_screenshot():
# 利用adb操控安卓手机截取图片到手机储存的根目录(获取当前界面手机截图)
os.system('adb shell screencap -p /sdcard/autojump.png')
# 从安卓手机里拿出这张图片到此文件夹下(下载当前这个截图到当前电脑文件夹下)
os.system('adb pull /sdcard/autojump.png .')
def jump(distance):
press_time = distance * 1.35
press_time = int(press_time)
# # adb执行 前四个参数是起跳点的横纵坐标(抓包知道320 410) 后是按压时间(一个像素点要按压1.35s,抓包)
cmd = 'adb shell input swipe 320 410 320 410 ' + str(press_time)
print(cmd)
os.system(cmd)
# 创建一个空白的图片对象/创建一张图片
fig = plt.figure()
pull_screenshot()
img = np.array(Image.open('autojump.png'))
#把获取的图片画在坐标轴上
im = plt.imshow(img, animated=True)
update = True
click_count = 0
cor = []
def update_data(): #更新图片
return np.array(Image.open('autojump.png'))
def updatefig(*args): #更新图片
global update
if update:
time.sleep(1.5)
pull_screenshot()
im.set_array(update_data())
update = False
return im,
#鼠标点击
#绑定鼠标单击
def on_click(event):
global update
global ix, iy # 起点与终点的坐标
global click_count
global cor
# 添加跳的起始点横纵坐标
ix, iy = event.xdata, event.ydata
coords = [(ix, iy)]
print('now = ', coords)
cor.append(coords)
click_count += 1
if click_count > 1:
click_count = 0
cor1 = cor.pop()
cor2 = cor.pop()
distance = (cor1[0][0] - cor2[0][0])**2 + (cor1[0][1] - cor2[0][1])**2 ##勾股定理,计算距离
distance = distance ** 0.5
print('distance = ', distance)
jump(distance)
update = True
fig.canvas.mpl_connect('button_press_event', on_click)
ani = animation.FuncAnimation(fig, updatefig, interval=50, blit=True)
plt.show()