对python的学习体会
对于java的掌握已经到了一个瓶颈,剩下需要学的大部分都在框架,听说python这门语言也很实用,就又花了一周多时间学习了python,其实看基本语法也就花了一天半,拥有java的基础看语法起来非常的快,关键词都基本一致,区别只在于格式,不过让我有点难绷的是python的缩进确定从属关系以及不用指定变量类型,这让Java为第一语言的我刚开始非常的不适应,后面打了几天代码才感觉好转,我感觉我是非常不乐意去看别人的python代码的,因为如果注释不够的话,需要看很久才能知道参数的类型,不过我也算是知道为什么很多人都说python方便了,因为它自带大量的三方类库,不用我们像java那样花很多时间去配置maven之类框架的环境变量,需要的不过是在开头import,想要分享给别人都不用打包,直接复制粘贴都能跑,听别人说python做脚本特别好,于是又花了3天时间完成了这个键鼠器以及这篇文章
自动化脚本(自动键鼠器)的介绍
我们首先说到脚本,什么是脚本?这个名字听起来好像高大上似的,其实能够帮助我们完成一些特定任务的都叫脚本,例如爬虫啦,抢票啦,连直接计算加减乘除其实都算,python之所以好写脚本,是因为有很多类库能够帮我们完成任务
我写的自动键鼠器的功能为记录鼠标和键盘的各项事件,然后能够一比一复刻出来,误差时间不超过0.2秒,用到的类库为pynput,xlwt,xlrd,time,先来介绍一下
pynput:能够监听和模拟鼠标和键盘
xlwt:能够将东西写到excel文件中,后面的wt其实为write
wlrd:能够读取excel文件,后面的rd其实为read
time:关于时间的各类方法
使用python实现原神下载自动化
逻辑说明
经过对类库的介绍,逻辑就很简单了,先使用pynput进行监听,监听到什么就用xlwt写入,完成之后通过wlrd进行读取,读取到什么就用pynput进行模拟,其中同时记录time的时间戳,能够保证监听和模拟的时间基本完全一致,为什么说是基本呢?因为监听写入和读取模拟python是要花额外时间的,不过非常的快,误差极小
pynput的监听
这个监听用的是官方给的几个方法,包括鼠标监听和键盘监听
鼠标监听
包括点击,滚动,释放其实还有个移动,不过我们的鼠标通过方法能够瞬移,就把他弃掉了。
需要监听的是左击还是右击,向上还是向下滚动,在什么位置点击和释放的
这里以鼠标点击为例
start=time.time() def on_click(x, y, button, pressed): global i global start duration = time.time() - start data = [x, y, duration] if pressed: if button == mouse.Button.left: table.write(i, 0, 1) for event in data: table.write(i, data.index(event)+1, event) table.write(i, 4, str(button)) i += 1 start = time.time() print("左击了") if button == mouse.Button.right: table.write(i,0,1) for event in data: table.write(i, data.index(event)+1,event) table.write(i, 4, str(button)) i += 1 start = time.time() print("右击了") 这里面的table就是xlwt造好的excel表,通过write(行数,列数,内容)进行写入
这里将时间戳开始start和事行数i以global声明为全局变量,这样就能确保每个事件都能被记录下来,同时我们也不用去考虑双击,在这里看来不过就是两次时间间隔很小的单击,每完成一次记录,start重置,行数加一
注意事项:这里的button不能直接写入,excel会报错不支持这种type,因此单独转成str,为什么不放到元组里一块str转了呢?这是因为后面我们读取类似坐标,时间戳信息时,进行复刻时要求是数字类型,如果放一块后面还得单独转回来。
其次,为了之后区分各项事件,可以看到我在所有行的第一列手动键入了一个数字
1为点击,2为松开,3为滚动
pynput监听到的点击和松开是分开的,因此需要额外记录松开
if not pressed: table.write(i, 0, 2) for event in data: table.write(i, data.index(event)+1, event) table.write(i, 4, str(button)) i += 1 start = time.time() print("放开了") 那么到这里,每个监听的格式就基本一模一样了,无非就是把类型,鼠标事件的坐标记录下来
键盘监听
这个只包括按下和放开
4为按下,5为放开
这里以按下为例
def on_press(key): global i global start '按下按键时执行。' try: duration = time.time() - start data = [key.char, duration] table.write(i, 0, 4) for event in data: table.write(i, data.index(event) + 1, event) i += 1 start = time.time() print("键盘按下了") except AttributeError: if key == Key.esc: book.save("record.xls") print("保存了") mouse_listener.stop() key_listener.stop() 可以看到逻辑和鼠标的也是一致,且按下会记录对应数字4
这里需要注意的是key和key.char
首先,excel像上面鼠标的button一样不接受key这个type,用str强转也不行,因为后面模拟的时候他按不出来,即使长的一模一样,他也会报“不是有效的key”,因此使用key.char,这个它自带的方法能写入excel,且读取正常
但问题也来了,key.char说明只能记录单个字符,而我们的键盘上是有特殊键的,如enter,table,f键这些,所以这时我们按特殊键会报错,因此要加入异常处理,在处理中我们可以规定按到esc就将excel保存,同时关闭两个监听器
在写入的时候,记得关闭excel表,不然会报错
关于监听器的启动
mouse_listener = mouse.Listener( on_click=on_click, on_scroll=on_scroll ) key_listener1= keyboard.Listener( on_press=on_press, on_release=on_release) mouse_listener.start() key_listener.start() while True: if input() == "q": exit() 如果我们去百度上搜监听器的使用的话,可以发现它不仅有上图这种形式的,还有一种带with的
例如
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
两种的区别在于with那个是阻塞式的,阻塞顾名思义堵住了,可以认为它自带了一个死循环,它在join完后还会继续join到线程中以实现监听,所以写在它后面的语句不能再实现,因此用with的话,键盘监听和鼠标监听无法同时进行
而我写的这种不是阻塞式的,所以后面要手动加个while True保持住,不然一运行就会直接停止,而且我们也知道了start启动方法就只需要一次,join则需要一直进行
读取和模拟
先来观察一下写好的excel

它的索引是从0列0行开始的,由于我们前面在写入的时候在每一行的开头写入了特定的数字,因此我们根据这个数字把它对应的逻辑给写到pynput的模拟当中去就好
def parse(sheet): i=0 m = mouse.Controller() k=keyboard.Controller() while i < sheet.nrows: #取本行指令的操作类型 cmdType = sheet.row(i)[0] if cmdType.value == 1: #1为点击 x=sheet.row(i)[1].value y=sheet.row(i)[2].value duration = sheet.row(i)[3].value turn=Button.left if sheet.row(i)[4].value=="Button.left"else Button.right time.sleep(duration) m.position=(x,y) m.press(turn) print("单击{0}".format(Button.left if sheet1.row(i)[4].value=="Button.left"else Button.right)) 以读取鼠标点击为例,sheet参数即为我们的excel表,读取鼠标的横纵坐标,操作时间和左右键,通过time.sleep()进行等待,controller的方法进行鼠标模拟
elif cmdType.value == 4: #4为键盘按下 str = sheet.row(i)[1].value duration=sheet.row(i)[2].value time.sleep(duration) k.press(str) 可以看到键盘也是如出一辙,我们可以看到鼠标的左右键可以通过if给他抠出来进行模拟,那么键盘当然也可以,不过鼠标只有左右中键,键盘却有三十几个特殊键,用起来不妥,因此我们在记录时需要避免使用特殊键,多用鼠标去进行额外功能的设定,此外,虽然特殊键打不进,但是键盘上这些配合shift的上标是可以正常录入的
file = 'record.xls' #打开文件 wb = xlrd.open_workbook(filename=file) #通过索引获取表格sheet页 sheet = wb.sheet_by_index(0) parse(sheet) 这里为打开excel表并进行模拟
键鼠器的应用场景
可以模拟一次从桌面到任何应用中干一些事,或者说模拟一些搬砖游戏的日常活动,如果需要缩短时间,可以在要解析的表中将等待时间那里改的短一些,而我写的这个的好处是记录人的判断时间,在同一台电脑上可以保证在应用响应时间变化不大的情况下完成所有操作
缺点:
一旦有一步没对上,后面全部会模拟失败
总结和体会
键鼠器的实现从逻辑上来说并不复杂,但需要对几个类库的语法进行学习并进行逻辑上的拼接,我觉得似乎一般的程序员大部分时间都在做这件事,不过能把轮子拼接好并让其跑起来我觉得也算一门本事了。编程最难的地方反而是怎样想出一个好的主意,编一个带什么功能的程序,这里还是需要一点想象力
如果这篇文章对你有帮助,希望能给个赞支持一下,有问题可以直接问我,看到了就会回复