目的很简单,统计每天做寮30的情况,以及每天是否做的是两章任务。目前这个工作是会长和副会长人工统计(每次一有活动就会chua chua掉排名)的,希望可以解放双手。
参考了御魂导出器和御魂放大镜,他们都提到了面向内存编程,但是又没有说怎么面向内存。
所以作为新手小白,我决定先写一个模拟点击的脚本先用着。
网上说脚本和外挂的很大区别在于,脚本不做修改,仅是把数据可视化显示/模拟人工操作,而外挂可能实现的是诸如锁血等骚东西。
环境配置
win32api:用于窗口控制
首先安装win32api,使用的指令是
pip install pywin32
安装好后就可以正常调用win32api,win32con等等
pytesseract:用于图像文字/数字提取
接着安装pytesseract,具体步骤及资源,请参考文末[参考资料3](http://www.inimei.cn/archives/297.html
具体实现
首先确认整个流程:①打开痒痒鼠PC端 ,点击到阴阳寮页面 ②切换到功勋界面 ③记录功勋+不断下翻。⑤后续的比对之类的并没有写,想的是用json的形式存储在本地文件中,每次进行更新比对
步骤一:确认用户已完成①步骤
def get_window_info(): # 获取阴阳师窗口信息
wdname = u'阴阳师-网易游戏'
handle = win32gui.FindWindow(0, wdname) # 获取窗口句柄
if handle == 0:
print("Error to find yys")
return None
else:
return win32gui.GetWindowRect(handle)
这一步中,是判断当前有没有打开PC端痒痒鼠
main函数中这样调用:
if __name__ == '__main__':
# 初始化窗口定位
window_size = get_window_info()
if window_size is not None:
initx = window_size[0]
inity = window_size[1]
得到的initx和inity就是痒痒鼠界面在整个屏幕的坐标值。
上图为痒痒鼠的阴阳寮界面,我们通过截图,得到右侧的功勋切换按钮,距离左上角的相对坐标:
windows自带的画图工具有一个好处,即是你将鼠标放置在图像上时, 左下角会实时显示鼠标对应的当前像素坐标。也就是说,(左上角x坐标 + 1002,左上角y坐标 + 367)这个像素点,就是我们鼠标在整个屏幕中放置的位置。
为了确认用户打开了正确页面,我们采用左上角的图像作为识别用图像
左上角局部图像
通过grab+绝对坐标的形式,截取需要的内容,还可以用过save保存,或是show显示
# 确认当前为管理页面
img_manage = pic_grab(40, 40, 300, 300, initx, inity)
# 查看图片
# img_manage.show()
# img_manage.save('manege_symb.jpg')
pic_grab函数是自定义用来截取绝对坐标的函数
def pic_grab(topx, topy, bottomx, bottomy, initx, inity):
return ImageGrab.grab((initx + topx, inity + topy, initx + bottomx, inity + bottomy))
截取了图片后,通过文末 参考资料1中提到的,模拟人工操作时,不全部采用OCR的方法,改为采用图像截取的办法,计算截取图像的平均像素值,然后比对整张图像和平均像素值的差异,得到图像的hash值。之后只需再次截取进行比对(比对时采用了汉明距离),即可知道是否正确进入界面,对图像进行判断
图像hash计算及汉明距离计算:
def get_hash(img): # 对图片计算hash值
img = img.resize((16, 16), Image.ANTIALIAS).convert('L') # 抗锯齿 灰度
avg = sum(list(img.getdata())) / 256 # 计算像素平均值
s = ''.join(map(lambda i: '0' if i < avg else '1', img.getdata())) # 每个像素进行比对,大于avg为1,反之为0
return ''.join(map(lambda j: '%x' % int(s[j:j+4], 2), range(0, 256, 4)))
def hamming(hash1, hash2, n=20): # 计算汉明距离
b = False
assert len(hash1) == len(hash2)
if sum(ch1 != ch2 for ch1, ch2 in zip(hash1, hash2)) < n:
b = True
return b
为了后续可以判断界面是否正确,我们预先需要先运行一遍正确的,并保存正确的hash值
img_manage_hash = get_hash(img_manage)
print(img_manage_hash)
步骤二:获取阴阳寮人数
终于用到ocr识别了,方法也很简单,首先同样的截取人数位置的图像,然后通过ocr识别图像内容,数字识别函数:
def pic_digit_read(path):
image = Image.open(path)
text = pytesseract.image_to_string(image, config = 'digits') # 数字识别
fil = filter(str.isdigit, text)
new_text = ''
for i in fil:
new_text += i
return int(new_text)
截取+调用过程:
# 获取总人数
img_tmp = pic_grab(315, 195, 357, 219, initx, inity)
img_tmp.save('peoNum.jpg')
peoNum = pic_digit_read('peoNum.jpg')
print(peoNum)
步骤三:移动并点击切换
为了不被痒痒鼠查出采用了外挂,我们将点击范围改为范围点击,即在一个可点击范围内,通过random函数实现较随机的点击。
def random_in_range(min, max): # 在给定范围内进行随机数
return min + int((max - min) * random.random())
按照你的需求依次点击相应位置即可
步骤四:开始识别 名字+功勋
分别截取名字,功勋,以及其他你想统计的信息,分别做ocr识别
这里名字部分由于出现了 日文/俄文/特殊符号,可能会有相应的问题,由于我们采用的是最简单的基本OCR库(扩展的需要安装很久我懒得全装了),所以可能识别不准确。
一开始我用的方法是,识别2次,然后做相似比对,不一致部分用*代替(一般是难识别字)。比如说 猥琐的哈哈,可能最终就存储成了*琐的哈哈。
后来我发现可以用灰度处理,把文字部分凸显(下面get_bin_table中的默认参数135,是通过我实践+肉眼得到的最佳值)。
实践方法是对同一批图像的每一张,通过从90,每次+10的形式,处理至180,挑出其中文字显示及识别均正确的图像,缩小上下限及变化幅度
最终发现在132-137范围处理结果最佳,因此定在了135。当然这个不是绝对准确的,如果时间及性能允许,多处理几次取众数可能更好一些。
文字识别部分代码:
def get_bin_table(threshold = 135):
# 获取灰度转二值的映射table
table = []
for i in range(256):
if i < threshold:
table.append(0)
else:
table.append(1)
return table
def pic_word_read():
image = Image.open('name_tmp.jpg')
imgry = image.convert('L')
table = get_bin_table()
out = imgry.point(table, '1')
text = pytesseract.image_to_string(out, lang='chi_sim') # 灰度处理后识别
text = text.replace(" ","").replace("\"","").replace("\'","").replace("\t","").replace("\\","")
print(text)
return text
下翻页
一页识别完了(应该可以识别5个),翻到下一页
# 滑动页面
# scoll_window(initx + random_in_range(448, 968), inity + random_in_range(170, 518), -352)
完整代码
完整代码请移步github项目
Github项目:《JustForFun - 痒痒鼠寮勋章自动统计》By ZaoZhe6666
参考资料
参考资料2 《游戏辅助脚本(python)》
网友评论