Python自动化脚本——涉及弹窗,自动登录,截图,获取用户权限,打包程序等

2020暑期XX银行实习-一个自动化脚本

很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取视频教程,电子书籍,以及课程的源代码!
QQ群:101677771

 

实习背景

有幸在2020年进行中国某银行金融科技中心进行时长一个月的实习,在金科部的开发工作主要是帮助开发了一款自动化的程序,可以实现自动登录网页,然后进行截图,在此工程中涉及到不少功能和技巧,特此写下记录。可能叙述和代码有错,欢迎大家一起交流。

主功能介绍

整个程序的流程,运行后弹出对话框填写查询的关键字,后续用于网页自动搜索到达指定网页,随后登录网页并自动运行至最后的指定网页,截图指定内容部分保存至文件夹后关闭。

获取用户权限和禁用鼠标键盘

在脚本自动运行的时候,防止用户误输入和误操作,需要禁止使用鼠标和键盘。利用一个函数ShellExecute,具体细节可看ShellExecuteA function。这里贴出一段代码,直接使用即可。

from __future__ import print_function
import ctypes, sys

if windll.shell32.IsUserAnAdmin():
    //运行的代码
else:
    if sys.version_info[0] == 3:
    	ctypes.windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 1)
    	exit()//因为即使没有权限也会运行,所以添加exit,使得没有权限时会退出程序。
    else:
    	//如果是python 2.x
        ctypes.windll.shell32.ShellExecuteW(None, u"runas", unicode(sys.executable), unicode(__file__), None, 1)
        exit()

值得注意的是,如果没有管理员运行,这里其实运行了两次,第一次没有权限,第二次获得权限后运行代码,所以我添加了一个退出的函数exit()。这是一个很有必要改进的点,日后有机会看看能否完善。

参考:https://blog.csdn.net/qq_17550379/article/details/79006655

对话框

通过使用pyautogui库来实现从对话框获取参数和警告对话框功能。

import pyautogui as pag

# 显示一个简单的带文字和OK按钮的消息弹窗。用户点击后返回button的文字。
pag.alert(text='对话框内部内容', title='对话框标题', button='按钮')
//例如:
a = pag.alert(text='要开始程序么?', title='请求框', button='OK')
print(a) # 输出结果为返回的OK

# 显示一个简单的带文字、OK和Cancel按钮的消息弹窗,用户点击后返回被点击button的文字,支持自定义数字、文字的列表。
pag.confirm(text='对话框内部内容', title='对话框标题', buttons=['OK', 'Cancel']) # OK和Cancel按钮的消息弹窗,其中按钮可以使用数字来设置个数
pag.confirm(text='', title='', buttons=range(10)) # 10个按键0-9的消息弹窗
//例如:
b = pag.confirm(text='', title='', buttons=range(10))
print(b) # 输出结果为点击的数字

# 可以输入的消息弹窗,带OK和Cancel按钮。用户点击OK按钮返回输入的文字,点击Cancel按钮返回None。可以设置一个默认输入。
pag.prompt(text='对话框内部内容', title='对话框标题', default='默认输入')

# 样式同prompt(),用于输入密码,消息用*表示。带OK和Cancel按钮。用户点击OK按钮返回输入的文字,点击Cancel按钮返回None。
pag.password(text='对话框内部内容', title='对话框标题', default='', mask='*')

主要使用了返回输入的对话框和警告框,从返回框获得ID后,用于后续的搜索,当自动运行过程中出错时,警告框可以提醒用户。

参考:https://www.jb51.net/article/183926.htm

使用谷歌浏览器chrome自动登录网页

使用谷歌浏览器的驱动进行自动化登录网页是一个常用的方法,这也是我自己以前使用的方法,但是这次登录的网页属于银行内部的内网,无法使用webdriver定位网页元素,无论是使用哪种方式都不行,所以只是使用驱动启到一个自动打开网页的功能,后续的用户登录,自动搜索等都是利用pyautogui的模拟鼠标键盘输入。

chromedriver

通常的网页自动登录使用chromedriver即可,可以参考Python实现网站自动登录—傻瓜教程。也非常推荐这种方法,因为模拟鼠标点击实在有些笨,只适合一些简单的自动脚本,但是适用面到可以说是很广了。

模拟鼠标点击以及键盘输入

键盘输入这个功能其实很多模块都有,这是比较需要的是鼠标的点击,这是一个比较愚蠢的方法,但却简单粗暴加实用,当然,很不灵活。主要使用库pyautogui

首先可以使用QQ或者微信的截图功能,获取屏幕上指定点的像素点坐标,记作cur_xcur_y

import pyautogui
pyautogui.click(x=cur_x, y=cur_y, button='left')
//x,y是要点击的位置,默认是鼠标当前位置
//button是要点击的按键,有三个可选值:‘left’, ‘middle’, ‘right’

输入用户名和密码使用模拟键盘输入即可,值得注意的是有几个注意点:

  • 输入前全选加删除,也就是ctrl+a再del
  • 不要模拟一个一个字母输入,很有可能受限于输入法的问题,使用字符串复制再粘贴
import pyautogui as pag
   """全选内容并删除"""
   pag.hotkey('ctrl','a')
   pag.press('delete')
  • 1
  • 2
  • 3
  • 4
import pyautogui as pag
import pyperclip
   """输入内容。使用了剪切板,可以忽略输入法问题!"""
   char = '用户名或密码'
   pyperclip.copy(char)
   pag.hotkey('ctrl','v')
  •  

其中我还使用该库的locateOnScreen函数进行像素匹配,判断截图是否已经达到了目标区域,和结束位置。有兴趣可以点击链接python 捕捉和模拟鼠标键盘操作,参考仍和第一部分一样。

参考:https://www.jb51.net/article/183926.htm

截图

截图这里有着太多方法,许多库都提供了方法,其实如果是通常可正常爬取的网页,推荐使用导出PDF,而不是截图,这样可以得到整个网页。截图正常情况下只能得到当前屏幕的内容。但由于银行内网的缘故,这里采用了webdriver的截图函数。

driver.save_screenshot("保存的地址")
  • 1

但是上面的函数只能够截取当前页面的图片,我们需要截取更多的图片,长图,网络上有现成的代码,可以实现分开截取图片最后拼接成长图。因为时间有些久远,忘记参考的链接,这里贴出代码:

"""截取长图"""
   window_height = driver.get_window_size()['height']  # 窗口高度
   page_height = driver.execute_script('return document.documentElement.scrollHeight')  # 页面高度
   driver.save_screenshot('分图.png')
   if page_height > window_height:
       n = page_height // window_height  # 需要滚动的次数
       base_mat = np.atleast_2d(Image.open('1.png'))  # 打开截图并转为二维矩阵

       for i in range(n):
           driver.execute_script(f'document.documentElement.scrollTop={window_height * (i + 1)};')
           time.sleep(.5)
           driver.save_screenshot(f'分图_{i}.png')  # 保存截图
           mat = np.atleast_2d(Image.open(f'分图_{i}.png'))  # 打开截图并转为二维矩阵
           base_mat = np.append(base_mat, mat, axis=0)  # 拼接图片的二维矩阵
       Image.fromarray(base_mat).save(char)

现在所使用的是利用的是,利用标志点是否出现在屏幕里,来截取指定区域的所有内容,具体情况看代码。

所有代码

"""自动脚本"""
"""登录网站并对流程截图"""
"""基本实现功能版"""
""""为解决有些电脑运行过慢,添加一个读取文本文件,加入等待时间的系数time_k"""
import time
import os
from selenium import webdriver
import sys
from ctypes import *
from PIL import Image
import numpy as np
from win32 import win32api, win32gui, win32print
from win32.lib import win32con
from win32.win32api import GetSystemMetrics
import pyperclip

screen_w = GetSystemMetrics (0)
screen_h = GetSystemMetrics (1)
import pyautogui as pag
def main(screen_w , screen_h):
   #读取时间参数
   try:
       time_k = Read_txt()
   except:
       time_k = 1

   # 判断时间参数
   if time_k>5 or time_k<0.2:
       pag.alert(text='时间参数设置不正常,请设置在0.2~5之间', title='警告', button='OK')
       exit()

   #权限获取
   Inner()

   #用户可以使用框输入需求ID,例如:GZ20073002
   demand_id = pag.prompt(text='请输入流程编号(请保证使用谷歌浏览器,且版本为83.0.4103相近)', title='查询业务流程', default='')
   if demand_id == None:
       exit()
   #分辨率判断

   #提示框,用于截图命名
   title = pag.prompt(text='请输入标题,用于结果命名(可不输)', title='标题名称输入', default='')
   if title == None:
       title = " "

   resolution_judgment(screen_w,screen_h)

   # 环境配置
   chromedriver = "C:\Program Files (x86)\Google\Chrome\Application"
   os.environ["webdriver.ie.driver"] = chromedriver

   driver = webdriver.Chrome()  # 选择Chrome浏览器
   driver.get('网址')  # 打开网站
   driver.maximize_window()  # 最大化谷歌浏览器


   time.sleep(2)
   try:
       #禁用鼠标键盘
       windll.user32.BlockInput(True)

       time.sleep(1*time_k)

       #输入用户名和密码
       username = ""  # 用户名
       #password = ""  # 密码
       password=Password()
       #鼠标移动到用户名
       Mouse_Click(1330,290)
       All_Del_Pag()
       Input_THING(username)


       #鼠标移动到密码
       Mouse_Click(1340,325)
       All_Del_Pag()
       Input_THING(password)

       Mouse_Click(1305,400)# 点击登录

       time.sleep(5*time_k)

       Mouse_Click(375,145)  # 点击个人主页
       time.sleep(0.5*time_k)
       Mouse_Click(110,269)  # 点击我的任务
       time.sleep(0.5*time_k)
       Mouse_Click(90,335)  # 点击已办任务
       time.sleep(4.5*time_k)

       #输入编码
       Mouse_Click(600,351)
       All_Del_Pag()
       Input_THING(demand_id)
       Mouse_Click(918,353)  # 点击确定
       time.sleep(2.5*time_k)

       Mouse_Click(1840,453)  # 点击查看
       time.sleep(5*time_k)

       try:
           driver.switch_to.window(driver.window_handles[1])
       except:
           windll.user32.BlockInput(False)
           pag.alert(text='页面不对!可能是网络原因\流程ID不存在\输入法问题,请检查后再尝试', title='警告', button='OK')
           driver.close()
           exit()

       #抓取一个特征,用于最后截图定位已经到底部
       try:
           pag.scroll(-90000)
           time.sleep(.5*time_k)
           flag_img = pag.screenshot(region=(206,817,25,25))
           time.sleep(.5*time_k)
           pag.scroll(90000)
       except:
           windll.user32.BlockInput(False)
           pag.alert(text='未知错误,请联系开发者', title='警告', button='OK')
           driver.close()

       time.sleep(.5*time_k)
       Mouse_Click(231,299)  # 流程查看
       time.sleep(.5*time_k)

       """开始截图,不断往下翻页截图,直到识别标志特征"""
       try:
           t = True
           i = 1
           while t:
               Html_Png(driver,'\\%s%d.png'%(title,i))
               if pag.locateOnScreen(flag_img):
                   t = False
               pag.scroll(-1000)
               i=i+1
       except:
           windll.user32.BlockInput(False)
           pag.alert(text='未知错误', title='警告', button='OK')
           driver.close()

       time.sleep(.5)
       windll.user32.BlockInput(False)
       #关闭驱动
       driver.close()

   except:
       windll.user32.BlockInput(False)
       driver.close()

def All_Del_Pag():
   #全选内容并删除
   pag.hotkey('ctrl','a')
   pag.press('delete')

def Input_THING(char):
   """输入内容。使用了剪切板,可以忽略输入法问题!"""
   pyperclip.copy(char)
   pag.hotkey('ctrl','v')

def Mouse_Click(x,y):
   #移动并点击
   pag.moveTo(x,y)
   pag.click()

def Html_Png(driver,char):
   """截图"""
   Png_root = Local_Adr_G(char)
   try:
       driver.save_screenshot(Png_root)
   except:
       print('截图出错')

def Html_LongPng(driver,char):
   #长截图功能,建行网站无法使用,通常网站可以
   window_height = driver.get_window_size()['height']  # 窗口高度
   page_height = driver.execute_script('return document.documentElement.scrollHeight')  # 页面高度
   driver.save_screenshot('分图.png')
   if page_height > window_height:
       n = page_height // window_height  # 需要滚动的次数
       base_mat = np.atleast_2d(Image.open('1.png'))  # 打开截图并转为二维矩阵

       for i in range(n):
           driver.execute_script(f'document.documentElement.scrollTop={window_height * (i + 1)};')
           time.sleep(.5)
           driver.save_screenshot(f'分图_{i}.png')  # 保存截图
           mat = np.atleast_2d(Image.open(f'分图_{i}.png'))  # 打开截图并转为二维矩阵
           base_mat = np.append(base_mat, mat, axis=0)  # 拼接图片的二维矩阵
       Image.fromarray(base_mat).save(char)

def Local_Adr(char):
   """获取当前文件路径"""
   root = os.path.dirname(sys.argv[0])
   root = root + char
   return root

def Local_Adr_G(char):
   """获取当前路径下的的流程截图文件路径"""
   root = os.path.dirname(sys.argv[0])+'\\流程截图'
   root = root + char
   return root
   
def Inner():
   #获取管理员权限
   if windll.shell32.IsUserAnAdmin():
       return
   else:
       windll.shell32.ShellExecuteW(None, "runas", sys.executable, __file__, None, 0)
       sys.exit()

def get_real_resolution():
   """获取真实的分辨率"""
   hDC = win32gui.GetDC(0)
   # 横向分辨率
   w = win32print.GetDeviceCaps(hDC, win32con.DESKTOPHORZRES)
   # 纵向分辨率
   h = win32print.GetDeviceCaps(hDC, win32con.DESKTOPVERTRES)
   return w, h

def resolution_change(x,y):
   """修改分辨率"""
   dm = win32api.EnumDisplaySettings(None, 0)
   dm.PelsWidth = x
   dm.PelsHeight = y
   dm.BitsPerPel = 32
   dm.DisplayFixedOutput = 0
   win32api.ChangeDisplaySettings(dm, 0)

def resolution_judgment(w,h):
   """分辨率判断"""
   real_resolution = get_real_resolution()
   screen_size = w,h
   screen_scale_rate = round(real_resolution[0] / screen_size[0], 2)
   if screen_size[0] == 1920:
       return
   else:
       if screen_scale_rate == 1:
           pag.alert(text='缩放比例已为100%,现在程序尝试自动设置分辨率,\n若没有成功请手动尝试设置960X540,并设置缩放比例为50%', title='说明', button='OK')
           resolution_change(1920,1080)
           exit()
       else:
           pag.alert(text='分辨率有误!!\n请点击左下角图标-设置-显示,设置分辨率和缩放比例\n(1920X1080,100% 或 960X540,50%)', title='警告', button='OK')
           exit()

def Read_txt():
   """读取文件获得时间参数"""
   path = os.path.dirname(sys.argv[0])+'\\time.txt'
   with open(path,"r") as f:
       data = f.readline()
       return float(data)

def Read_Password():
   path = os.path.dirname(sys.argv[0])+'\\reg.txt'
   with open(path,"r") as f:
       data = f.readline()
       return data    

def Password():
   pa=Read_Password()
   ch=""
   for i in range(0,len(pa),5):
       asc=int(str(int(pa[i:i+5])*11)[-3:])
       ch=ch+chr(asc)
   return ch


if __name__ == '__main__':
   main(screen_w , screen_h)
  • 0
    点赞
  • 0
    评论
  • 5
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

打赏
文章很值,打赏犒劳作者一下
相关推荐
©️2020 CSDN 皮肤主题: 深蓝海洋 设计师:CSDN官方博客 返回首页

打赏

Python_sn

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值