Playwright,微软浏览器自动化教程(二)

Playwright,微软浏览器自动化教程(二)
核心概念,建议结合第一节的内容具体理解

1、Browser

这是一个浏览器实例,脚本运行需要首先打开浏览器实例

# playwright.brwoser_type.action(**kwargs)可以理解为指定浏览器内核
browser = playwright.chromium.launch(channel="chrome",headless=False)
# launch是最常用的一个函数,他有大量的参数,这里介绍常用的的
headless    是否显示GUI,默认是TRUE不显示
channel     指定浏览器版本,"chrome", "chrome-beta", "chrome-dev", "chrome-canary",
proxy       浏览器代理设置
timeout     等待超时时间,默认30000ms(30s)
slow_mo     减慢操作速度,浮点型,一边可以看清楚操作

顺便说一下,playwright的所有操作都有自动等待的功能,时间都是30s

2、Browser contexts

这个是独立的浏览器,隐身对话,意思是每一个Beowser contexts都是独立的,互相之间没有关系,等于说全都是新装的浏览器。

# 根据浏览器内核创建浏览器
context = browser.new_context(accept_downloads=False)
# 创建新页面
page = context.new_page()

2.1、browser.new_context

# browser.new_context的参数包括所有跟浏览器设置相关的
# 可以理解为根据浏览器创建一个新的浏览器
accept_downloads      是否下载所有附件,默认False不下载
geolocation           设定经纬度
user_agent            设定user agent
viewport              设定页面大小,规格,例如1280*720
offline               离线模式加载

2.2、context

# context就是浏览器层面的操作
context.new_page()      返回一个新页面
context.pages           返回所有打开的页面[list]
context.add_cookies([cookie_object1, cookie_object2])   添加cookie
context.cookies()       返回cookie
context.wait_for_event(event, **kwargs) 等待event完成

3、Pages and frames

一个 Browser contexts 有多个pages,一个 page 是一个单独的tab,或者弹出窗口。用于导航到url ,或者与页面交互,比如点击,输入文字等。
一个 page 有多个 Frame (框架),框架内的操作无法通过page.**操作,只能通过page.Frame.func()操作,但是通常在录制模式下,他会自动识别是否是框架内的操作,如果不懂怎么定位框架,那么可以使用录制模式来找。


3.1、Pages

大部分操作都是在page层面的,所以page有最多的函数

from playwright.sync_api import sync_playwright
# 这是一个创建页面,定位到指定链接,并截屏保存的例子
def run(playwright):
    webkit = playwright.webkit
    browser = webkit.launch()
    context = browser.new_context()
    page = context.new_page()
    page.goto("https://example.com")
    page.screenshot(path="screenshot.png")
    browser.close()

with sync_playwright() as playwright:
    run(playwright)

常用的函数有,一般看名字就知道是干嘛的

page.click(selector, **kwargs)
page.content()      # 获取页面的html
page.screenshot(**kwargs)
page.goto(url, **kwargs)
page.pdf(**kwargs)
page.reload(**kwargs)
page.wait_for_timeout(timeout)
page.get_attribute(selector, name, **kwargs)

# page的expect_**函数需要注意
# 这个类型的函数一般都伴随这with使用
# 下面这个例子就是点击按钮后,改变了页面框架
with page.expect_event("framenavigated") as event_info:
    page.click("button")
frame = event_info.value
#这样的还有很多,比如,大都用在交互的对象改变的情况下
page.expect_file_chooser(**kwargs)
page.expect_navigation(**kwargs)
page.expect_popup(**kwargs)

# 个人推荐注意这几个is的方法,在等待页面的时候很有用
page.is_disabled/(selector, **kwargs)
is_editable,is_enabled,is_hidden,is_visible

# 还有一个特殊的方法
page.locator(selector)      # 定位页面元素,返回的是locator对象

3.2、Frame

frame的操作大部分跟page一样,只不过framepage下一级的,可以理解为在page里嵌套的一个小页面。但是还是有一点不一样。
page里分为主框架和子框架,这里有一个框架树的例子,大家可以运行下试试。

from playwright.sync_api import sync_playwright

def run(playwright):
    firefox = playwright.firefox
    browser = firefox.launch()
    page = browser.new_page()
    page.goto("https://www.theverge.com")
    dump_frame_tree(page.main_frame, "")
    browser.close()

def dump_frame_tree(frame, indent):
    print(indent + frame.name + '@' + frame.url)
    for child in frame.child_frames:
        dump_frame_tree(child, indent + "    ")

with sync_playwright() as playwright:
    run(playwright)

其方法大部分都与page一样,不在赘述,注意的是
page.frame(**kwargs),这个可以用来选择Frame,并返回Frame对象,所以对Frame的操作有一下两种方法。

# 直接定位Frame操作
page.frame(name="frame-name").click('text=hello')

#返回Frame对象操作
frame = page.frame(name="frame-name")
frame.click('text=hello')

4、Selectors

Playwright可以通过css,XPath,HTML等选择元素,像id,data-test-id,或者像上面演示的,通过text内容。
这里有一些例子

# Using data-test-id= selector engine
page.click('data-test-id=foo')

# CSS and XPath selector engines are automatically detected
page.click('div')
page.click('//html/body/div')

# Find node by text substring
page.click('text=Hello w')

# 通过 >> 链接相同或不同的选择器
# Click an element with text 'Sign Up' inside of a #free-month-promo.
page.click('#free-month-promo >> text=Sign Up')

我推荐使用浏览器的开发者模式来寻找选择器:
[图片上传失败...(image-372c61-1649499671696)]

5、Auto-waiting

所有的操作都会等待元素可见,或者可操作之后才会进行,也就是自带等待时间,但是如果要自己加等待的话不推荐使用time.sleep(5),而是用page.wait_for_timeout(5000)
这里也可以使用page的wait操作:

page.wait_for_event(event, **kwargs)
page.wait_for_function(expression, **kwargs)
page.wait_for_load_state(**kwargs)
page.wait_for_selector(selector, **kwargs)
page.wait_for_timeout(timeout)
page.wait_for_url(url, **kwargs)

6、Evaluation Argument

像 page.evaluate(expression, **kwargs) 这样的剧作家评估方法采用单个可选参数。 此参数可以是 Serializable 值和 JSHandle 或 ElementHandle 实例的混合。 句柄会自动转换为它们所代表的值。

# A primitive value.
page.evaluate('num => num', 42)

# An array.
page.evaluate('array => array.length', [1, 2, 3])

# An object.
page.evaluate('object => object.foo', { 'foo': 'bar' })

# A single handle.
button = page.query_selector('button')
page.evaluate('button => button.textContent', button)

# Alternative notation using elementHandle.evaluate.
button.evaluate('(button, from) => button.textContent.substring(from)', 5)

# Object with multiple handles.
button1 = page.query_selector('.button1')
button2 = page.query_selector('.button2')
page.evaluate("""o => o.button1.textContent + o.button2.textContent""",
    { 'button1': button1, 'button2': button2 })

# Object destructuring works. Note that property names must match
# between the destructured object and the argument.
# Also note the required parenthesis.
page.evaluate("""
    ({ button1, button2 }) => button1.textContent + button2.textContent""",
    { 'button1': button1, 'button2': button2 })

# Array works as well. Arbitrary names can be used for destructuring.
# Note the required parenthesis.
page.evaluate("""
    ([b1, b2]) => b1.textContent + b2.textContent""",
    [button1, button2])

# Any non-cyclic mix of serializables and handles works.
page.evaluate("""
    x => x.button1.textContent + x.list[0].textContent + String(x.foo)""",
    { 'button1': button1, 'list': [button2], 'foo': None })

参考文章:
参考链接

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容