手头有个小需求:针对一个 antd 框架的后台系统,一一点开父菜单及其子菜单(2、3、4 级),检查所有菜单对应页面是否正常。
想着,playwright 目前在自动化工具的热度升高,正好了解一下,按这个试试玩玩。
因为涉及到系统登录,所以采用 connect 方式:先浏览器启动参数增加--remote-debugging-port=9222,登录好系统,然后运行脚本。
本来这个是小脚本,但用了简单的递归:自动化这么多年都是流水帐,首次有 leetcode 照进现实的感觉,就稍微分享一下
下面是东拼西凑的脚本(说明见注释):
# coding:utf-8
import asyncio,typing
from playwright.async_api import async_playwright,ProxySettings
from playwright.async_api._generated import Page,Browser,ElementHandle
currentUrl="" # 记录当前url,用于报错时记录对应url
async def connectChromium(playwright,debugPort=9222)->typing.Union[None,Browser]:
"""
连接一个已经打开debug的chromium: 启动参数--test-type --remote-debugging-port=9222
"""
try:
browser = await playwright.chromium.connect_over_cdp("http://localhost:%d"%debugPort)
return browser
except Exception as e:
print("连接chromium出现异常:%s"%str(e))
async def checkReponse(response):
"""
检查response
:param response:
:return:
"""
global currentUrl
contenType=await response.header_value("content-type")
if contenType and (contenType.find("json")>=0 or contenType.find("html")>=0):
# 检查html及json响应的状态
if not response.ok:
print(f'response error: request[{response.request.url}] status is not ok on page[{currentUrl}]')
async def loopOaMenu(page:Page,locObj:ElementHandle):
"""
遍历Antd类的菜单
:param page:
:return:
"""
global currentUrl
menuLocAll = await locObj.query_selector_all("li.ant-menu-submenu") # 非叶子菜单
for menuLoc in menuLocAll:
p_class = await menuLoc.get_attribute('class')
if p_class.find('ant-menu-submenu-open') < 0: # 非叶子菜单未展开
await menuLoc.click() # 点击展开
await asyncio.sleep(1)
await loopOaMenu(page,menuLoc) # 递归
subMenuLinkLocAll = await menuLoc.query_selector_all("ul.ant-menu-sub li[role=menuitem] a") # 叶子菜单
for linkLoc in subMenuLinkLocAll:
await linkLoc.click() # 点击叶子菜单
currentUrl = page.url # 写入当前url
await asyncio.sleep(1.5)
#print(await linkLoc.get_attribute("href"))
async def job(page:Page):
"""
主任务
"""
await page.goto("https://oa.xxx.com/#/") # 访问首页
await asyncio.sleep(2)
await loopOssMenu(page,await page.query_selector("aside"))
async def run():
global currentUrl
async with async_playwright() as playwright:
browser = await connectChromium(playwright)
if not browser:
print("chrome连接失败")
return
default_context = browser.contexts[0]
page = default_context.pages[0]
page.on("console",lambda msg: print(f"console error: {msg.text} on page[{currentUrl}]") if msg.type == "error" else None)
# 监听控制台中异常消息
page.on("response",checkReponse)
# 监听响应处理
await job(page)
await browser.close()
if __name__=='__main__':
asyncio.run(run())