教你用 Python 实现微信跳一跳(Mac+iOS版)


Posted in Python onJanuary 04, 2018

这几天看网上好多微信跳一跳破解了,不过都是安卓的,无奈苹果不是开源也没办法。这个教程是 Mac + iOS , 要下xcode 要配置环境小白估计是没戏了,有iOS 开发经验的可以看看 。不过其实可以没事帮同事刷一下,让他们请吃个饭什么的,哈哈。 

先发个战果

教你用 Python 实现微信跳一跳(Mac+iOS版)

一.WebDriverAgent

首先去 https://github.com/facebook/WebDriverAgent 下一份代码

教你用 Python 实现微信跳一跳(Mac+iOS版) 

选择 WebDriverAgentRunner 用真机 然后 test 运行一下 , 看到IP地址就说明成功了

教你用 Python 实现微信跳一跳(Mac+iOS版) 

手机打开跳一跳 ,在电脑上访问 IP , 如我的 192.168.1.101:8100/inspector ,可以看到下面的东西

教你用 Python 实现微信跳一跳(Mac+iOS版) 

如果电脑访问 ip连接有问题 在命令行执行下面命令

$   iproxy 8100 8100

用电脑代理一下手机的8100端口

二. 去下载 wechat_jump_game

去github 下 https://github.com/wangshub/wechat_jump_game

下好之后要下载一些依赖库

$  pip install -r requirements.txt

记得 拷贝 wechat_jump_game-master ./config/iPhone 目录下对应的设备配置文件,重命名并替换到 ./config.json

教你用 Python 实现微信跳一跳(Mac+iOS版) 

将手机点击到《跳一跳》小程序界面,然后在命令行 执行 下面代码就可以自由的刷分了

$ python wechat_jump_auto_iOS.py

------------------------我是分割线------------------------------

既然身为码农就要有跟技术死磕的精神 ,比较技术就是饭碗嘛 。个人觉得python 是个神奇的东西,有着丰富的库,上可以写爬虫抓数据,下可以玩web服务。

代码核心其实就是计算出棋子和下一个砖的距离 然后 乘以 一个弹跳系数 来得到 press_time

源代码PO出来学习一下

# coding: utf-8
import os
import shutil
import time
import math
import wda
from PIL import Image, ImageDraw
import random
import json
# === 思路 ===
# 核心:每次落稳之后截图,根据截图算出棋子的坐标和下一个块顶面的中点坐标,
# 根据两个点的距离乘以一个时间系数获得长按的时间
# 识别棋子:靠棋子的颜色来识别位置,通过截图发现最下面一行大概是一条直线,就从上往下一行一行遍历,
#  比较颜色(颜色用了一个区间来比较)找到最下面的那一行的所有点,然后求个中点,
#  求好之后再让 Y 轴坐标减小棋子底盘的一半高度从而得到中心点的坐标
# 识别棋盘:靠底色和方块的色差来做,从分数之下的位置开始,一行一行扫描,由于圆形的块最顶上是一条线,
#  方形的上面大概是一个点,所以就用类似识别棋子的做法多识别了几个点求中点,
#  这时候得到了块中点的 X 轴坐标,这时候假设现在棋子在当前块的中心,
#  根据一个通过截图获取的固定的角度来推出中点的 Y 坐标
# 最后:根据两点的坐标算距离乘以系数来获取长按时间(似乎可以直接用 X 轴距离)
# TODO: 解决定位偏移的问题
# TODO: 看看两个块中心到中轴距离是否相同,如果是的话靠这个来判断一下当前超前还是落后,便于矫正
# TODO: 一些固定值根据截图的具体大小计算
# TODO: 直接用 X 轴距离简化逻辑
with open('config.json', 'r') as f:
 config = json.load(f)
# Magic Number,不设置可能无法正常执行,请根据具体截图从上到下按需设置
under_game_score_y = config['under_game_score_y'] # 截图中刚好低于分数显示区域的 Y 坐标,300 是 1920x1080 的值,2K 屏、全面屏请根据实际情况修改
press_coefficient = config['press_coefficient'] # 长按的时间系数,请自己根据实际情况调节
piece_base_height_1_2 = config['piece_base_height_1_2'] # 二分之一的棋子底座高度,可能要调节
piece_body_width = config['piece_body_width']  # 棋子的宽度,比截图中量到的稍微大一点比较安全,可能要调节
time_coefficient = config['press_coefficient']
# 模拟按压的起始点坐标,需要自动重复游戏请设置成“再来一局”的坐标
if config.get('swipe'):
 swipe = config['swipe']
else:
 swipe = {
 "x1": 320,
 "y1": 410,
 "x2": 320,
 "y2": 410
 }
c = wda.Client()
s = c.session()
screenshot_backup_dir = 'screenshot_backups/'
if not os.path.isdir(screenshot_backup_dir):
 os.mkdir(screenshot_backup_dir)
def pull_screenshot():
 c.screenshot('1.png')
def jump(distance):
 press_time = distance * time_coefficient / 1000
 print('press time: {}'.format(press_time))
 s.tap_hold(200, 200, press_time)
def backup_screenshot(ts):
 # 为了方便失败的时候 debug
 if not os.path.isdir(screenshot_backup_dir):
 os.mkdir(screenshot_backup_dir)
 shutil.copy('1.png', '{}{}.png'.format(screenshot_backup_dir, ts))
def save_debug_creenshot(ts, im, piece_x, piece_y, board_x, board_y):
 draw = ImageDraw.Draw(im)
 # 对debug图片加上详细的注释
 draw.line((piece_x, piece_y) + (board_x, board_y), fill=2, width=3)
 draw.line((piece_x, 0, piece_x, im.size[1]), fill=(255, 0, 0))
 draw.line((0, piece_y, im.size[0], piece_y), fill=(255, 0, 0))
 draw.line((board_x, 0, board_x, im.size[1]), fill=(0, 0, 255))
 draw.line((0, board_y, im.size[0], board_y), fill=(0, 0, 255))
 draw.ellipse((piece_x - 10, piece_y - 10, piece_x + 10, piece_y + 10), fill=(255, 0, 0))
 draw.ellipse((board_x - 10, board_y - 10, board_x + 10, board_y + 10), fill=(0, 0, 255))
 del draw
 im.save('{}{}_d.png'.format(screenshot_backup_dir, ts))
def set_button_position(im):
 # 将swipe设置为 `再来一局` 按钮的位置
 global swipe_x1, swipe_y1, swipe_x2, swipe_y2
 w, h = im.size
 left = w / 2
 top = 1003 * (h / 1280.0) + 10
 swipe_x1, swipe_y1, swipe_x2, swipe_y2 = left, top, left, top
def find_piece_and_board(im):
 w, h = im.size
 print("size: {}, {}".format(w, h))
 piece_x_sum = 0
 piece_x_c = 0
 piece_y_max = 0
 board_x = 0
 board_y = 0
 scan_x_border = int(w / 8) # 扫描棋子时的左右边界
 scan_start_y = 0 # 扫描的起始y坐标
 im_pixel = im.load()
 # 以50px步长,尝试探测scan_start_y
 for i in range(under_game_score_y, h, 50):
 last_pixel = im_pixel[0, i]
 for j in range(1, w):
  pixel = im_pixel[j, i]
  # 不是纯色的线,则记录scan_start_y的值,准备跳出循环
  if pixel[0] != last_pixel[0] or pixel[1] != last_pixel[1] or pixel[2] != last_pixel[2]:
  scan_start_y = i - 50
  break
 if scan_start_y:
  break
 print("scan_start_y: ", scan_start_y)
 # 从scan_start_y开始往下扫描,棋子应位于屏幕上半部分,这里暂定不超过2/3
 for i in range(scan_start_y, int(h * 2 / 3)):
 for j in range(scan_x_border, w - scan_x_border): # 横坐标方面也减少了一部分扫描开销
  pixel = im_pixel[j, i]
  # 根据棋子的最低行的颜色判断,找最后一行那些点的平均值,这个颜色这样应该 OK,暂时不提出来
  if (50 < pixel[0] < 60) and (53 < pixel[1] < 63) and (95 < pixel[2] < 110):
  piece_x_sum += j
  piece_x_c += 1
  piece_y_max = max(i, piece_y_max)
 if not all((piece_x_sum, piece_x_c)):
 return 0, 0, 0, 0
 piece_x = piece_x_sum / piece_x_c
 piece_y = piece_y_max - piece_base_height_1_2 # 上移棋子底盘高度的一半
 for i in range (int (h / 3), int (h * 2 / 3)):
 last_pixel = im_pixel[0, i]
 if board_x or board_y:
  break
 board_x_sum = 0
 board_x_c = 0
 for j in range(w):
  pixel = im_pixel[j, i]
  # 修掉脑袋比下一个小格子还高的情况的 bug
  if abs(j - piece_x) < piece_body_width:
  continue
  # 修掉圆顶的时候一条线导致的小 bug,这个颜色判断应该 OK,暂时不提出来
  if abs(pixel[0] - last_pixel[0]) + abs(pixel[1] - last_pixel[1]) + abs(pixel[2] - last_pixel[2]) > 10:
  board_x_sum += j
  board_x_c += 1
 if board_x_sum:
  board_x = board_x_sum / board_x_c
 # 按实际的角度来算,找到接近下一个 board 中心的坐标 这里的角度应该是30°,值应该是tan 30°, math.sqrt(3) / 3
 board_y = piece_y - abs(board_x - piece_x) * math.sqrt(3) / 3
 if not all((board_x, board_y)):
 return 0, 0, 0, 0
 return piece_x, piece_y, board_x, board_y
def main():
 while True:
 pull_screenshot()
 im = Image.open("./1.png")
 # 获取棋子和 board 的位置
 piece_x, piece_y, board_x, board_y = find_piece_and_board(im)
 ts = int(time.time())
 print(ts, piece_x, piece_y, board_x, board_y)
 if piece_x == 0:
  return
 set_button_position(im)
 distance = math.sqrt((board_x - piece_x) ** 2 + (board_y - piece_y) ** 2)
 jump(distance)
 save_debug_creenshot(ts, im, piece_x, piece_y, board_x, board_y)
 backup_screenshot(ts)
 time.sleep(random.uniform(1, 1.1)) # 为了保证截图的时候应落稳了,多延迟一会儿
if __name__ == '__main__':
 main()

总结

以上所述是小编给大家介绍的教你用 Python 来玩微信跳一跳(Mac+iOS版),希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
Python中optionParser模块的使用方法实例教程
Aug 29 Python
Python搭建APNS苹果推送通知推送服务的相关模块使用指南
Jun 02 Python
利用Python中SocketServer 实现客户端与服务器间非阻塞通信
Dec 15 Python
Python探索之创建二叉树
Oct 25 Python
利用 python 对目录下的文件进行过滤删除
Dec 27 Python
Python模拟百度自动输入搜索功能的实例
Feb 14 Python
Python实现定时自动关闭的tkinter窗口方法
Feb 16 Python
python+selenium实现简历自动刷新的示例代码
May 20 Python
ORM Django 终端打印 SQL 语句实现解析
Aug 09 Python
python numpy之np.random的随机数函数使用介绍
Oct 06 Python
Django 允许局域网中的机器访问你的主机操作
May 13 Python
Python多线程的退出控制实现
Aug 10 Python
基于python实现在excel中读取与生成随机数写入excel中
Jan 04 #Python
python实现简易云音乐播放器
Jan 04 #Python
Python语言描述连续子数组的最大和
Jan 04 #Python
一个月入门Python爬虫学习,轻松爬取大规模数据
Jan 03 #Python
Python编程pygame模块实现移动的小车示例代码
Jan 03 #Python
python编程实现随机生成多个椭圆实例代码
Jan 03 #Python
Python通过Pygame绘制移动的矩形实例代码
Jan 03 #Python
You might like
PHP安装问题
2006/10/09 PHP
phpmailer在服务器上不能正常发送邮件的解决办法
2014/07/08 PHP
php检索或者复制远程文件的方法
2015/03/13 PHP
Laravel最佳分割路由文件(routes.php)的方式
2016/08/04 PHP
javascript常用正则表达式汇总
2015/07/31 Javascript
js实现选中复选框文字变色的方法
2015/08/14 Javascript
JS基于ocanvas插件实现的简单画板效果代码(附demo源码下载)
2016/04/05 Javascript
详释JavaScript执行环境与执行栈
2019/04/02 Javascript
VsCode与Node.js知识点详解
2019/09/05 Javascript
微信提示 在浏览器打开 效果实现过程解析
2019/09/10 Javascript
vue实现简单跑马灯效果
2020/05/25 Javascript
[01:09:24]Ti4开幕式
2014/07/19 DOTA
python使用socket进行简单网络连接的方法
2015/04/29 Python
Python控制多进程与多线程并发数总结
2016/10/26 Python
python通过pip更新所有已安装的包实现方法
2017/05/19 Python
python文字和unicode/ascll相互转换函数及简单加密解密实现代码
2019/08/12 Python
Python Web框架之Django框架cookie和session用法分析
2019/08/16 Python
Pandas聚合运算和分组运算的实现示例
2019/10/17 Python
Python partial函数原理及用法解析
2019/12/11 Python
Pytorch 的损失函数Loss function使用详解
2020/01/02 Python
python实现扑克牌交互式界面发牌程序
2020/04/22 Python
Python3安装模块报错Microsoft Visual C++ 14.0 is required的解决方法
2020/07/28 Python
python实现简单的井字棋游戏(gui界面)
2021/01/22 Python
Pytorch自定义Dataset和DataLoader去除不存在和空数据的操作
2021/03/03 Python
介绍一下Java中的static关键字
2012/05/12 面试题
园林设计师自荐信
2013/11/18 职场文书
中国梦口号
2014/06/13 职场文书
党政领导班子四风问题对照检查材料思想汇报
2014/10/02 职场文书
2014年班务工作总结
2014/12/02 职场文书
秋收起义观后感
2015/06/11 职场文书
董事长年会致辞
2015/07/29 职场文书
中学生国庆节演讲稿2015
2015/07/30 职场文书
初中数学课堂教学反思
2016/02/17 职场文书
Golang 正则匹配效率详解
2021/04/25 Golang
Spring Boot 排除某个类加载注入IOC的操作
2021/08/02 Java/Android
Win11筛选键导致键盘失灵怎么解决? Win11关闭筛选键的技巧
2022/04/08 数码科技