Python使用selenium模拟浏览器实现自动化操作

数据工作者在日常工作中经常遇到需要定期更新报表数据的情况,一般而言大公司给到业务的数据权限相对有限,有的并不能直接访问数据库,而是使用报表系统来定期提取数据,手动导出导入本地数据库再进行分析。

本来可以自动化运行的场景被‘报表系统’给割裂,设计上用来方便业务人员的系统却在某些程度上成了天花板,一定要想方设法的突破它。

selenium介绍

selenium是自动化测试工具集,就是写好代码可以自动调用浏览器测试页面功能和性能的工具,使用人群大多是测试工程师,因为它有一整套测试功能,能够很好的契合各种类型网站的测试工作。

它支持多浏览器,WebDriver可以从Python等语言直接调用,所有操作与人工操作轨迹一致,不容易被定为为及机器人,以上这些优点让selenium很适合与Python一起完成初级的自动化功能,比如自动登陆、自动下载数据等

场景分析

既然是自动化测试工作,那肯定也可以简单改动用来自动化大多数需要网页操作的工作,这个案例里我们使用Selenium-WebDriver来自动化登陆报表系统,下载定期报表并导入本机SQL数据库。

首先安装Selenium,Win+R唤出控制台

pip install Selenium

定义地址或加入系统path后就可以直接调用Chrome模拟了,当然还可以自定义一些列Chrome参数等,这里需要下载文件所以自定义了默认下载地址,其它自定义参数可以从Chrome或对应浏览器的文档里查找。

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import os
import time
import sys
ChromePath = r'‪ChromeDriver地址'
PlatformUrl = 'http://abdata.ab.com:7001/anbang/'
DataFolds=r'默认地址'
chromeOptions = webdriver.ChromeOptions()
prefs = {"download.default_directory": DataFolds}
chromeOptions.add_experimental_option("prefs", prefs)
接下来使用Selenium打开窗口,访问地址
BotSession = webdriver.Chrome(chrome_options=chromeOptions)
BotSession.get(PlatformUrl)

Selenium可以定为元素后依靠Click(),Submit()等函数完成点击和提交等动作,定为元素的方法较多,这里使用最容易入门的Xpath,按F12打开调试台再需要点击的元素上点右键检查,即可定位到源代码,在高亮的源代码上右键copy-Xpath即可负责对应的Xpath,使用Click或Send_Keys即可完成输入和点击动作。

BotSession.find_element_by_xpath('//*[@id="data_statistics"]').click()

BotSession.find_element_by_xpath('//*[@id="j_username"]').send_keys('账号')

BotSession.find_element_by_xpath('//*[@id="j_password"]').send_keys('密码')

大部分网站拥有验证码部分,这里可以使用前文所述的Python自动验证码功能,也可以Pause后手动输入验证码,演示代码使用自动识别验证码方式

BotSession.get_screenshot_as_file(DataFolds + '/test.png')#全屏截屏
element = BotSession.find_element_by_xpath('//*[@id="identify"]')
left = int(element.location['x']*1.5)
top = int(element.location['y']*1.5)
right = int(element.location['x']*1.5 + element.size['width']*1.5)
bottom = int(element.location['y']*1.5 + element.size['height']*1.5)
from PIL import Image
im = Image.open(DataFolds + '/test.png')
im = im.crop((left, top, right, bottom))
im.save(DataFolds + '/test.png')
Filepath =DataFolds + r'\test.png'
#识别验证码
sys.path.append(r'验证码地址')
import CodeDetect
Res=CodeDetect.CodeDetect(Filepath)
ResDict=eval(str(Res,encoding = "utf-8"))
BotSession.find_element_by_xpath('//*[@id="yanZheng"]').send_keys(ResDict['result']['code'])
BotSession.find_element_by_xpath('//*[@id="yanZheng"]').send_keys(Keys.ENTER)
有的时候页面有自动跳出的通知公告,我们可以使用try模式尝试点击或跳过
try :
CloseExlment=BotSession.find_element_by_xpath('/html/body/div/div[1]/div[2]/a')
except :
pass
else:
CloseExlment.click()
有时候页面有iframe框架Selenium并不能智能识别,这里需要阅读代码并切换到iframe内
BotSession.switch_to.frame("frameContent")
BotSession.find_element_by_xpath('//*[@id="hrefB"]').click()
有时一个列表内的许多任务只有一个是我们所需要的,这时需要根据唯一可以确定的值来识别任务,代码示例里用的是设置任务自动执行的时间来识别,这样不同的任务设置不同的时间即可
for i in range(9) :
CheckXptah = '//*[@id="datagrid-row-r4-2-'+str(i) +'"]/td[3]/div'
TimeStr = BotSession.find_element_by_xpath(CheckXptah).text
TaskTime=time.strptime(TimeStr,"%Y-%m-%d %H:%M:%S")
if TaskTime.tm_mday == (time.localtime().tm_mday -1) and TaskTime.tm_hour == 23 : #按小时寻找昨天的执行任务
Rightxpath = '//*[@id="datagrid-row-r4-2-'+str(i)+'"]/td[6]/div/span'
break
else : pass
BotSession.find_element_by_xpath(Rightxpath).click()
大部分时候已经下载好待导入SQL的文件放置在统一的位置,我们使用os模块调用重命名和移动功能挪过去即可
os.chdir(DataFolds)
time.sleep(15)
os.rename("导出文件名.txt" , "导入文件名.txt")
import shutil
shutil.move(r'原位置',r'新位置')
运行完毕后退出或使用windows计划任务导入SQL即可
BotSession.quit()

成品如下

自动登陆报表系统,调用接口识别验证码,判断是否有弹窗关闭,跳入iframe切换到定时任务页面,使用任务执行时间区分目标任务,点击下载数据,移动到指定位置,调用计划任务导入SQL,Enjoy

pending..