微软出品的UI自动化测试工具Playwright(三)

博客 动态
0 152
羽尘
羽尘 2023-04-19 09:27:28
悬赏:0 积分 收藏

微软出品的UI自动化测试工具Playwright(三)

微软出品的UI自动化测试工具Playwright(三)

网址 说明
https://playwright.dev/ 官网首页
https://playwright.dev/python/docs/intro Python部分入口
https://github.com/microsoft/playwright-python github,python入口
https://github.com/microsoft/playwright-python/releases python部分的release notes

本文基于 playwright 1.32.1 发布于 2023-3-30

学习前你得有html、css、xpath等基础,最好有selenium基础,我是对比来讲解的
微软出品的UI自动化测试工具Playwright(一)
微软出品的UI自动化测试工具Playwright(二)
微软出品的UI自动化测试工具Playwright(三)

⑤实例

通过一个个实例来讲述Playwright的能力

实例一: 打开某某网站

  • 参考代码

    from playwright.sync_api import sync_playwright
    
    with sync_playwright() as p:
        browser = p.chromium.launch(headless=False)
        page = browser.new_page()
        page.goto("https://www.baidu.com")
    
  • 执行效果:打开百度后自动关闭

  • 对比selenium,这是有点麻烦的


  • playwright是个包(文件夹),里面主要是3个部分

    • sync_api:同步,入门你用的最多的是这个
    • driver
    • async_api:异步
  • sync_playwright是一个函数,返回值类型是PlaywrightContextManager

    def sync_playwright() -> PlaywrightContextManager:
        return PlaywrightContextManager()
    
  • 从名字上看得出是个上下文管理器,所以你可以用with来处理

    钻进去你能看到__enter__和__exit
    
        def __enter__(self) -> SyncPlaywright:
    
  • 而这个SyncPlaywright是有很多属性的,主要的就是我们要打开的几个浏览器

        def chromium(self) -> "BrowserType":
            """Playwright.chromium
    
            This object can be used to launch or connect to Chromium, returning instances of `Browser`.
    
            Returns
            -------
            BrowserType
            """
            return mapping.from_impl(self._impl_obj.chromium)
        
        def firefox(self) -> "BrowserType":
        def webkit(self) -> "BrowserType":
    
  • BrowserType则是浏览器类型类,它的launch方法是重要的方法,参数非常多,一般用到的就是headless,赋值False就是有头(能看到页面)。返回的是浏览器实例。

  • 在playwright中你仅有一个浏览器实例是作不了什么的,你必须要打开一个页面

  • Browser有一些方法属性,其中new_page是用来打开新的页面的,返回类型是Page

  • 玩过selenium的同学应该知道,Page对象是你最多了解的部分

  • Page对象属性方法详见附录一

实例二: 登录开源论坛

  • 前面了解了打开网页

  • 下面就涉及UI自动化测试最重要的定位了

  • 参考代码

    from playwright.sync_api import sync_playwright
    
    with sync_playwright() as p:
        browser_type = p.chromium
        browser = browser_type.launch(headless=False)
        page = browser.new_page()
        page.goto("http://114.116.2.138:8090/forum.php")
        page.locator('#ls_username').fill('admin')
        page.locator('#ls_password').fill('123456')
        page.locator('.pn.vm').click()
        page.wait_for_timeout(5000)
    
  • 可以看到我们使用了css语法来定位

  • page对象的locator方法中就可以去塞一个css表达式来定位元素

  • 而这个元素也是非常重要的对象,其类型是Locator,这个对象的属性方法可以参考附录二

  • 此处的等待要注意,在页面上等待不建议使用time.sleep,而是应该用page的wait_for_timeout

  • 参考代码2

    from playwright.sync_api import sync_playwright
    
    with sync_playwright() as p:
        browser_type = p.chromium
        browser = browser_type.launch(headless=False)
        page = browser.new_page()
        page.goto("http://114.116.2.138:8090/forum.php")
        page.fill('#ls_username','admin')
        page.fill('#ls_password','123456')
        page.click('.pn.vm')
        page.wait_for_timeout(5000)
    
  • 的确,locator都可以省略的,直接在fill或者click上写表达式

实例三: 获取百度热点

  • 参考代码

    from playwright.sync_api import sync_playwright
    with sync_playwright() as pw:
        browser = pw.chromium.launch(headless=False)  
        page = browser.new_page()
        page.goto('https://www.baidu.com')
        hot_news = page.locator('.title-content-title').all_text_contents()
        for hot_new in hot_news:
            print(hot_new)
    
  • 上述代码是ok的,但是你如果从selenium转过来,是比较别扭的

  • 因为page.locator('.title-content-title')定位元素在实例二中提到了,但此处表达式.title-content-title是有多个元素的

  • 在selenium中如果定位到了多个,你操作的是第一个,但playwright用locator的做法不一样,这多少有点不习惯。

  • 此处all_text_contents()的返回是个list,其内容就是我们热点的文本信息

    ['红树林边的瞩望', '带你体验中老友谊之旅', '中央转移支付首破十万亿 钱去哪儿了', '云南玉溪山火蔓延 火场燃烧迅猛', '银行发现7位数存款5年未动急寻人', '台媒:大陆禁航从27分钟变6小时']
    

  • 我们可以看看如果定位到一个元素的话,它的输出是没问题的

    from playwright.sync_api import sync_playwright
    with sync_playwright() as pw:
        browser = pw.chromium.launch(headless=False)
        page = browser.new_page()
        page.goto('https://www.baidu.com')
        # .hotsearch-item:nth-child(1) .title-content-title 这个表达式就定位到一个元素
        hot_news = page.locator('.hotsearch-item:nth-child(1) .title-content-title')
        print(hot_news.text_content())
    
  • 如果你定位到多个元素,就不行了

    from playwright.sync_api import sync_playwright
    with sync_playwright() as pw:
        browser = pw.chromium.launch(headless=False)
        page = browser.new_page()
        page.goto('https://www.baidu.com')
        hot_news = page.locator('.title-content-title')
        print(hot_news.text_content())
    
    Traceback (most recent call last):
      File "D:\pythonProject\AutoTest\DemoPlaywright0413\demos\demo_openpage.py", line 7, in <module>
        print(hot_news.text_content())
      File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\sync_api\_generated.py", line 17562, in text_content
        self._sync(self._impl_obj.text_content(timeout=timeout))
      File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_sync_base.py", line 104, in _sync
        return task.result()
      File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_locator.py", line 564, in text_content
        return await self._frame.text_content(
      File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_frame.py", line 605, in text_content
        return await self._channel.send("textContent", locals_to_params(locals()))
      File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_connection.py", line 61, in send
        return await self._connection.wrap_api_call(
      File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_connection.py", line 461, in wrap_api_call
        return await cb()
      File "D:\pythonProject\AutoTest\DemoPlaywright0413\venv\lib\site-packages\playwright\_impl\_connection.py", line 96, in inner_send
        result = next(iter(done)).result()
    playwright._impl._api_types.Error: Error: strict mode violation: locator(".title-content-title") resolved to 6 elements:
        1) <span class="title-content-title">红树林边的瞩望</span> aka get_by_role("link", name=" 红树林边的瞩望")
        2) <span class="title-content-title">带你体验中老友谊之旅</span> aka get_by_role("link", name="3 带你体验中老友谊之旅")
        3) <span class="title-content-title">中央转移支付首破十万亿 钱去哪儿了</span> aka get_by_role("link", name="1 中央转移支付首破十万亿 钱去哪儿了")
        4) <span class="title-content-title">云南玉溪山火蔓延 火场燃烧迅猛</span> aka get_by_role("link", name="4 云南玉溪山火蔓延 火场燃烧迅猛")
        5) <span class="title-content-title">银行发现7位数存款5年未动急寻人</span> aka get_by_role("link", name="2 银行发现7位数存款5年未动急寻人")
        6) <span class="title-content-title">台媒:大陆禁航从27分钟变6小时</span> aka get_by_role("link", name="5 台媒:大陆禁航从27分钟变6小时")
    
    =========================== logs ===========================
    waiting for locator(".title-content-title")
    ============================================================
    
    进程已结束,退出代码为 1
    
    

  • 然playwright还有一些其他的定位方法

实例四: 验证码破解登录

  • 参考代码

    from playwright.sync_api import sync_playwright
    with sync_playwright() as pw:
        browser = pw.chromium.launch(headless=False)
        page = browser.new_page()
        page.goto('http://121.5.150.55:8090/forum.php')
        page.locator('#ls_username').fill('admin')
        page.locator('#ls_password').fill('123456')
        page.locator('.pn.vm').click()
        code_bytes = page.locator("[id^='vseccode_cSA']>img").screenshot()
        import ddddocr
        ocr = ddddocr.DdddOcr()
        code_text = ocr.classification(code_bytes)
        page.locator("input[id^='seccodeverify_cSA']").fill(code_text)
        page.locator("[name='loginsubmit']").click()
    
  • 在这个案例中,我们主要用到了元素的screenshot(),返回的是一个bytes对象

  • 然后经过ddddocr处理可以得到其文本

实例五: 相对定位

  • 仅供参考

  • 实例代码

    from playwright.sync_api import sync_playwright
    with sync_playwright() as pw:
        browser = pw.chromium.launch(headless=False)
        page = browser.new_page()
        page.goto('http://121.41.14.39:8088/index.html')
        page.locator('input:above(#password)').fill('sq1')
        page.locator('#password:near(#username)').fill('123')
        page.locator('#code:left-of(img)').fill('999999')
        page.locator('#submitButton:below(#code)').click()
        page.wait_for_timeout(5000)
    

实例六: 论坛的悬停登录

from playwright.sync_api import sync_playwright
with sync_playwright() as pw:
    browser = pw.chromium.launch(headless=False)  
    page = browser.new_page()  
    page.goto('http://114.116.2.138:8090/forum.php')
    qmenu_locator = page.locator('#qmenu')
    qmenu_locator.hover()
    page.click('.xi2>strong')
    page.fill('[id^=username_L]','admin')
    page.fill('[id^=password3_L]','123456')
    page.click('[name=loginsubmit].pn.pnc')
    page.wait_for_timeout(5000)

实例七: 论坛的发帖

from playwright.sync_api import sync_playwright
with sync_playwright() as pw:
    browser = pw.chromium.launch(headless=False)  
    page = browser.new_page()  
    page.goto('http://114.116.2.138:8090/forum.php')
    page.fill('#ls_username','admin')
    page.fill('#ls_password','123456')
    page.keyboard.press('Enter')
    page.wait_for_timeout(2000)  
    page.click('text=默认版块')
    page.click('css=#newspecial')
    page.fill('#subject','帖子标题')
    page.frame_locator('#e_iframe').locator('#editorheader+body').fill('帖子内容')  #frame切换
    page.click('#postsubmit')
    page.wait_for_timeout(5000)

附录

Page对象属性方法

属性 说明
accessibility 可访问性
add_init_script
add_script_tag
add_style_tag
bring_to_front
check
click
close
content
context 上下文
dblclick 双击
dispatch_event
drag_and_drop
emulate_media
eval_on_selector
eval_on_selector_all
evaluate
evaluate_handle
expect_console_message
expect_download
expect_event
expect_file_chooser
expect_navigation
expect_popup
expect_request
expect_request_finished
expect_response
expect_websocket
expect_worker
expose_binding
expose_function
fill
focus
frame
frame_locator
frames
get_attribute
get_by_alt_text
get_by_label
get_by_placeholder
get_by_role
get_by_test_id
get_by_text
get_by_title
go_back
go_forward
goto 跳转到指定页面
hover
inner_html
inner_text
input_value
is_checked
is_closed
is_disabled
is_editable
is_enabled
is_hidden
is_visible
keyboard 键盘操作入口,返回Keyboard
locator 定位元素
main_frame
mouse 鼠标操作入口,返回Mouse
on
once
opener
pause
pdf
press
query_selector
query_selector_all
reload 页面刷新
remove_listener
request
route
route_from_har
screenshot 截图
select_option
set_checked
set_content
set_default_navigation_timeout
set_default_timeout
set_extra_http_headers
set_input_files
set_viewport_size
tap
text_content
title 标题
touchscreen
type
uncheck
unroute
url url
video
viewport_size
wait_for_event
wait_for_function
wait_for_load_state
wait_for_selector
wait_for_timeout 等待,参数是毫秒,float
wait_for_url
workers

Locator对象属性方法

属性 说明
all 所有元素
all_inner_texts
all_text_contents 所有文本内容
blur
bounding_box
check
clear 清空
click 点击
count 元素个数
dblclick 双击
dispatch_event
drag_to 拖拽
element_handle
element_handles
evaluate
evaluate_all
evaluate_handle
fill 输入内容
filter
first
focus
frame_locator
get_attribute
get_by_alt_text 通过alt属性的文本定位
get_by_label
get_by_placeholder
get_by_role
get_by_test_id
get_by_text
get_by_title
highlight
hover
inner_html
inner_text
input_value
is_checked
is_disabled
is_editable
is_enabled
is_hidden
is_visible
last
locator
nth 下标
on
once
page
press
remove_listener
screenshot 元素截图
scroll_into_view_if_needed
select_option
select_text
set_checked
set_input_files
tap
text_content
type
uncheck
wait_for

get_by_role所支持的标签

[
            "alert",
            "alertdialog",
            "application",
            "article",
            "banner",
            "blockquote",
            "button",
            "caption",
            "cell",
            "checkbox",
            "code",
            "columnheader",
            "combobox",
            "complementary",
            "contentinfo",
            "definition",
            "deletion",
            "dialog",
            "directory",
            "document",
            "emphasis",
            "feed",
            "figure",
            "form",
            "generic",
            "grid",
            "gridcell",
            "group",
            "heading",
            "img",
            "insertion",
            "link",
            "list",
            "listbox",
            "listitem",
            "log",
            "main",
            "marquee",
            "math",
            "menu",
            "menubar",
            "menuitem",
            "menuitemcheckbox",
            "menuitemradio",
            "meter",
            "navigation",
            "none",
            "note",
            "option",
            "paragraph",
            "presentation",
            "progressbar",
            "radio",
            "radiogroup",
            "region",
            "row",
            "rowgroup",
            "rowheader",
            "scrollbar",
            "search",
            "searchbox",
            "separator",
            "slider",
            "spinbutton",
            "status",
            "strong",
            "subscript",
            "superscript",
            "switch",
            "tab",
            "table",
            "tablist",
            "tabpanel",
            "term",
            "textbox",
            "time",
            "timer",
            "toolbar",
            "tooltip",
            "tree",
            "treegrid",
            "treeitem",
        ]

元素状态

元素状态(英) 元素状态(中) 说明(英)
Attached 附着 Element is considered attached when it is connected to a Document or a ShadowRoot.
元素连接到DOM或者ShadowRoot则认为元素是附着的
Visible 可见 Element is considered visible when it has non-empty bounding box and does not have visibility:hidden computed style. Note that elements of zero size or with display:none are not considered visible.
元素的可见意味着它有边界并且没有visibility:hidden,注意元素大小为0或者具有 display:none则认为是不可见的
Stable 稳定的 Element is considered stable when it has maintained the same bounding box for at least two consecutive animation frames
元素在至少两个连续的动画帧中保持相同的边界框时被认为是稳定的
Enabled 使能 Element is considered enabled unless it is a <button>, <select>, <input> or <textarea> with a disabled property.
元素如果是 <button>, <select>, <input> or <textarea>且具有disabled属性就认为是非使能的,否则都是使能的
Editable 可编辑 Element is considered editable when it is enabled and does not have readonly property set.
元素是可编辑的,意味着它一定是使能的且没有readonly属性
Receivces Events 接收事件 element is considered receiving pointer events when it is the hit target of the pointer event at the action point. For example, when clicking at the point (10;10), Playwright checks whether some other element (usually an overlay) will instead capture the click at (10;10)
posted @ 2023-04-19 09:11  松勤吴老师  阅读(0)  评论(0编辑  收藏  举报
回帖
    羽尘

    羽尘 (王者 段位)

    2335 积分 (2)粉丝 (11)源码

     

    温馨提示

    亦奇源码

    最新会员