Playwright,微軟瀏覽器自動(dòng)化教程(二)
核心概念同窘,建議結(jié)合第一節(jié)的內(nèi)容具體理解
1、Browser
這是一個(gè)瀏覽器實(shí)例部脚,腳本運(yùn)行需要首先打開(kāi)瀏覽器實(shí)例
# playwright.brwoser_type.action(**kwargs)可以理解為指定瀏覽器內(nèi)核
browser = playwright.chromium.launch(channel="chrome",headless=False)
# launch是最常用的一個(gè)函數(shù)想邦,他有大量的參數(shù),這里介紹常用的的
headless 是否顯示GUI,默認(rèn)是TRUE不顯示
channel 指定瀏覽器版本委刘,"chrome", "chrome-beta", "chrome-dev", "chrome-canary",
proxy 瀏覽器代理設(shè)置
timeout 等待超時(shí)時(shí)間丧没,默認(rèn)30000ms(30s)
slow_mo 減慢操作速度,浮點(diǎn)型锡移,一邊可以看清楚操作
順便說(shuō)一下呕童,playwright的所有操作都有自動(dòng)等待的功能,時(shí)間都是30s
2淆珊、Browser contexts
這個(gè)是獨(dú)立的瀏覽器夺饲,隱身對(duì)話,意思是每一個(gè)Beowser contexts都是獨(dú)立的,互相之間沒(méi)有關(guān)系往声,等于說(shuō)全都是新裝的瀏覽器擂找。
# 根據(jù)瀏覽器內(nèi)核創(chuàng)建瀏覽器
context = browser.new_context(accept_downloads=False)
# 創(chuàng)建新頁(yè)面
page = context.new_page()
2.1、browser.new_context
# browser.new_context的參數(shù)包括所有跟瀏覽器設(shè)置相關(guān)的
# 可以理解為根據(jù)瀏覽器創(chuàng)建一個(gè)新的瀏覽器
accept_downloads 是否下載所有附件浩销,默認(rèn)False不下載
geolocation 設(shè)定經(jīng)緯度
user_agent 設(shè)定user agent
viewport 設(shè)定頁(yè)面大小贯涎,規(guī)格,例如1280*720
offline 離線模式加載
2.2慢洋、context
# context就是瀏覽器層面的操作
context.new_page() 返回一個(gè)新頁(yè)面
context.pages 返回所有打開(kāi)的頁(yè)面[list]
context.add_cookies([cookie_object1, cookie_object2]) 添加cookie
context.cookies() 返回cookie
context.wait_for_event(event, **kwargs) 等待event完成
3塘雳、Pages and frames
一個(gè) Browser contexts 有多個(gè)pages,一個(gè) page 是一個(gè)單獨(dú)的tab普筹,或者彈出窗口败明。用于導(dǎo)航到url ,或者與頁(yè)面交互斑芜,比如點(diǎn)擊肩刃,輸入文字等。
一個(gè) page 有多個(gè) Frame (框架)杏头,框架內(nèi)的操作無(wú)法通過(guò)page.**操作盈包,只能通過(guò)page.Frame.func()操作,但是通常在錄制模式下醇王,他會(huì)自動(dòng)識(shí)別是否是框架內(nèi)的操作呢燥,如果不懂怎么定位框架,那么可以使用錄制模式來(lái)找寓娩。
3.1叛氨、Pages
大部分操作都是在page層面的,所以page有最多的函數(shù)
from playwright.sync_api import sync_playwright
# 這是一個(gè)創(chuàng)建頁(yè)面棘伴,定位到指定鏈接寞埠,并截屏保存的例子
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)
常用的函數(shù)有,一般看名字就知道是干嘛的
page.click(selector, **kwargs)
page.content() # 獲取頁(yè)面的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_**函數(shù)需要注意
# 這個(gè)類型的函數(shù)一般都伴隨這with使用
# 下面這個(gè)例子就是點(diǎn)擊按鈕后焊夸,改變了頁(yè)面框架
with page.expect_event("framenavigated") as event_info:
page.click("button")
frame = event_info.value
#這樣的還有很多仁连,比如,大都用在交互的對(duì)象改變的情況下
page.expect_file_chooser(**kwargs)
page.expect_navigation(**kwargs)
page.expect_popup(**kwargs)
# 個(gè)人推薦注意這幾個(gè)is的方法阱穗,在等待頁(yè)面的時(shí)候很有用
page.is_disabled/(selector, **kwargs)
is_editable饭冬,is_enabled,is_hidden揪阶,is_visible
# 還有一個(gè)特殊的方法
page.locator(selector) # 定位頁(yè)面元素昌抠,返回的是locator對(duì)象
3.2、Frame
frame的操作大部分跟page一樣鲁僚,只不過(guò)frame是page下一級(jí)的炊苫,可以理解為在page里嵌套的一個(gè)小頁(yè)面裁厅。但是還是有一點(diǎn)不一樣。
page里分為主框架和子框架劝评,這里有一個(gè)框架樹(shù)的例子,大家可以運(yùn)行下試試姐直。
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)
声畏,這個(gè)可以用來(lái)選擇Frame,并返回Frame對(duì)象姻成,所以對(duì)Frame的操作有一下兩種方法插龄。
# 直接定位Frame操作
page.frame(name="frame-name").click('text=hello')
#返回Frame對(duì)象操作
frame = page.frame(name="frame-name")
frame.click('text=hello')
4、Selectors
Playwright可以通過(guò)css
,XPath
,HTML
等選擇元素科展,像id
,data-test-id
均牢,或者像上面演示的,通過(guò)text內(nèi)容才睹。
這里有一些例子
# 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')
# 通過(guò) >> 鏈接相同或不同的選擇器
# Click an element with text 'Sign Up' inside of a #free-month-promo.
page.click('#free-month-promo >> text=Sign Up')
我推薦使用瀏覽器的開(kāi)發(fā)者模式來(lái)尋找選擇器:
[圖片上傳失敗...(image-372c61-1649499671696)]
5徘跪、Auto-waiting
所有的操作都會(huì)等待元素可見(jiàn),或者可操作之后才會(huì)進(jìn)行琅攘,也就是自帶等待時(shí)間垮庐,但是如果要自己加等待的話不推薦使用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) 這樣的劇作家評(píng)估方法采用單個(gè)可選參數(shù)。 此參數(shù)可以是 Serializable 值和 JSHandle 或 ElementHandle 實(shí)例的混合剧辐。 句柄會(huì)自動(dòng)轉(zhuǎn)換為它們所代表的值寒亥。
# 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 })
參考文章:
參考鏈接