Playwright是Microsoft在2020年初開源的新一代自動(dòng)化測(cè)試工具恳不,它的功能類似于Selenium怀酷、Pyppeteer等,都可以驅(qū)動(dòng)瀏覽器進(jìn)行各種自動(dòng)化操作剃毒。它的功能也非常強(qiáng)大宝剖,對(duì)市面上主流瀏覽器都提供了支持洁闰,API功能簡(jiǎn)潔又強(qiáng)大。雖然誕生的比較晚万细,但是發(fā)展得非称嗣迹火熱。
在Pyppeteer已經(jīng)不再維護(hù)的年代赖钞,擁有Playwright這個(gè)開源工具是非常棒的選擇腰素,文檔豐富,功能強(qiáng)大仁烹。
安裝方式
conda config --add channels conda-forge
conda config --add channels microsoft
conda install playwright
playwright install
上述命令的具體運(yùn)行過(guò)程是下載Playwright并將其打包為Chromium耸弄、Firefox和Webkit安裝瀏覽器二進(jìn)制文件咧虎。
特點(diǎn)
- Playwright支持當(dāng)前所有主流瀏覽器卓缰,包括Chrome和Edge(基于Chromium)、Firefox、Safari(基于Webkit)征唬,提供完善的自動(dòng)化控制的API捌显。
- Playwright支持移動(dòng)端頁(yè)面的測(cè)試,使用設(shè)備模擬技術(shù)可以在移動(dòng)web瀏覽器中測(cè)試響應(yīng)式web應(yīng)用程序总寒。
- Playwright支持所有瀏覽器的Headless模式和非Headless模式的測(cè)試扶歪。
- Playwright的安裝配置非常的簡(jiǎn)單,安裝過(guò)程中會(huì)自動(dòng)安裝對(duì)應(yīng)瀏覽器的驅(qū)動(dòng)摄闸,不需要額外的配置WebDriver等善镰。
- Playwright提供了大量的與自動(dòng)化相關(guān)的API,當(dāng)頁(yè)面加載時(shí)會(huì)自動(dòng)等待對(duì)應(yīng)節(jié)點(diǎn)的加載年枕,大大的簡(jiǎn)化了編寫API的難度炫欺。
使用方式
在python腳本中導(dǎo)入Playwright,并啟動(dòng)3種瀏覽器(Chromium熏兄、Friefox和webkit)的其中一種品洛。Playwright支持兩種編寫模式,一種是Pyppeter一樣的異步模式摩桶,另一種是像Selenium一樣的同步模式桥状,我們可以根據(jù)實(shí)際的需要選擇不同的模式。
下面我們先來(lái)看看一個(gè)基本 同步模式的例子:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
for browser_type in [p.chromium, p.firefox, p.webkit]:
browser = browser_type.launch(headless=False)
page = browser.new_page()
page.goto("https://www.baidu.com")
page.screenshot(path=f"screenshot-{browser_type.name}.png")
print(page.title())
browser.close()
首先在這里我們導(dǎo)入了sync_playwright方法硝清,然后調(diào)用這個(gè)方法辅斟,該方法返回的是一個(gè)PlaywrightContextManager對(duì)象,可以將其理解為瀏覽器的上下文管理器芦拿,這里將其賦值給變量p砾肺。接著調(diào)用PlaywrightContextManager對(duì)象的chromium、firefox防嗡、webkit瀏覽器實(shí)例变汪,接著使用for循環(huán)依次去執(zhí)行它們的launch方法,同時(shí)設(shè)置headless為False蚁趁。
這里有一個(gè)注意點(diǎn):如果launch沒(méi)有設(shè)置為Flase裙盾,默認(rèn)是無(wú)頭模式啟動(dòng)瀏覽器,我們看不到任何的窗口他嫡。
launch方法返回的是一個(gè)瀏覽器(Browser)對(duì)象番官,我們將其復(fù)制為browser變量,然后調(diào)用new_page方法钢属,相當(dāng)于是新建一個(gè)選顯卡徘熔,返回page對(duì)象并賦值給變量page,接下來(lái)就是調(diào)用page對(duì)象的一系列自動(dòng)化API進(jìn)行操作淆党。當(dāng)頁(yè)面加載完畢之后生成截圖酷师、控制臺(tái)輸出結(jié)果就退出讶凉,上面的代碼,調(diào)用了page對(duì)象的兩個(gè)方法:
1山孔、screenshot:參數(shù)傳一個(gè)文件的名稱懂讯,這樣截圖就會(huì)自動(dòng)保存為該文件的名稱。
2台颠、title:返回頁(yè)面的標(biāo)題褐望。
這時(shí)當(dāng)前目錄便會(huì)產(chǎn)生三個(gè)截圖文件,都是百度的首頁(yè)串前,文件名中都帶有瀏覽器的名稱瘫里,如圖所示:
控制臺(tái)運(yùn)行結(jié)果:
百度一下,你就知道
百度一下荡碾,你就知道
百度一下减宣,你就知道
除了上面所描述的同步模式之外,Playwright還支持異步模式玩荠,如果在項(xiàng)目中使用了asyncio漆腌,那么就應(yīng)該是考慮要采用異步模式,使用異步的API阶冈,寫法如下:
import asyncio
from playwright.async_api import async_playwright
async def main():
async with async_playwright() as p:
for browser_type in [p.chromium, p.firefox, p.webkit]:
browser = await browser_type.launch()
page = await browser.new_page()
await page.goto("https://www.baidu.com")
await page.screenshot(path=f"screenshot-{browser_type.name}.png")
print(await page.title())
await browser.close()
asyncio.run(main())
從上面的代碼可以看出闷尿,整個(gè)寫法和同步模式是很相似的。
注意:
1女坑、導(dǎo)入的是async_playwright方法
2填具、在寫法上添加 async/await 關(guān)鍵字。
代碼生成
Playwright還有一個(gè)強(qiáng)大的功能匆骗,那就是可以錄制我們?cè)跒g覽器的操作劳景,并將操作時(shí)的代碼自動(dòng)生成。這個(gè)功能可以通過(guò)Playwright命令調(diào)用codegen來(lái)實(shí)現(xiàn)碉就,我們先看看codegen命令都有什么參數(shù)盟广。
playwright codegen --help
結(jié)果類似如下:
Usage: npx playwright codegen [options] [url]
open page and generate code for user actions
Options:
-o, --output <file name> saves the generated script to a file
--target <language> language to generate, one of javascript, test, python, python-async, csharp (default:
"python")
-b, --browser <browserType> browser to use, one of cr, chromium, ff, firefox, wk, webkit (default: "chromium")
--channel <channel> Chromium distribution channel, "chrome", "chrome-beta", "msedge-dev", etc
--color-scheme <scheme> emulate preferred color scheme, "light" or "dark"
--device <deviceName> emulate device, for example "iPhone 11"
--geolocation <coordinates> specify geolocation coordinates, for example "37.819722,-122.478611"
--ignore-https-errors ignore https errors
--load-storage <filename> load context storage state from the file, previously saved with --save-storage
--lang <language> specify language / locale, for example "en-GB"
--proxy-server <proxy> specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"
--save-storage <filename> save context storage state at the end, for later use with --load-storage
--save-trace <filename> record a trace for the session and save it to a file
--timezone <time zone> time zone to emulate, for example "Europe/Rome"
--timeout <timeout> timeout for Playwright actions in milliseconds (default: "10000")
--user-agent <ua string> specify user agent string
--viewport-size <size> specify browser viewport size in pixels, for example "1280, 720"
-h, --help display help for command
Examples:
$ codegen
$ codegen --target=python
$ codegen -b webkit https://example.com
在上面可以看到有幾個(gè)選項(xiàng),比如-o表示輸出代碼文件的名稱瓮钥;--target表示所使用的語(yǔ)言筋量,默認(rèn)是python,即會(huì)生成同步模式的操作代碼碉熄,如果傳入的是python-async則會(huì)生成異步模式的操作代碼桨武;-b表示使用的瀏覽器類型,默認(rèn)是Chrome瀏覽器锈津;--device可以模擬使用手機(jī)瀏覽器呀酸;--lang表示設(shè)置瀏覽器語(yǔ)言,--timeout可以設(shè)置頁(yè)面加載超時(shí)時(shí)間琼梆。
了解這些用法之后性誉,我們就來(lái)嘗試啟動(dòng)Chrome瀏覽器窿吩,然后將操作結(jié)果輸出到test3.py,命令如下:
playwright codegen -o test3.py --target python-async
這時(shí)候就彈出了一個(gè)Chrome瀏覽器艾栋,同時(shí)在右側(cè)會(huì)輸出一個(gè)腳本窗口,實(shí)時(shí)顯示操作對(duì)應(yīng)的代碼蛉顽。
可以看到瀏覽器還會(huì)高亮顯示正在操作的節(jié)點(diǎn)蝗砾,同時(shí)還顯示了節(jié)點(diǎn)名稱。
在操作的過(guò)程中代碼是實(shí)時(shí)變化的携冤。操作完畢之后即可關(guān)閉瀏覽器悼粮,Playwright會(huì)生成一個(gè)test3.py文件,內(nèi)容如下:
import asyncio
from playwright.async_api import Playwright, async_playwright
async def run(playwright: Playwright) -> None:
browser = await playwright.chromium.launch(headless=False)
context = await browser.new_context()
# Open new page
page = await context.new_page()
# Go to https://www.baidu.com/
await page.goto("https://www.baidu.com/")
# Click input[name="wd"]
await page.click("input[name=\"wd\"]")
# Click input[name="wd"]
await page.click("input[name=\"wd\"]")
# Fill input[name="wd"]
await page.fill("input[name=\"wd\"]", "如何榜上富婆")
# Click text=百度一下
# async with page.expect_navigation(url="https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E5%A6%82%E4%BD%95%E6%A6%9C%E4%B8%8A%E5%AF%8C%E5%A9%86&fenlei=256&rsv_pq=ca59e3ec000cf6aa&rsv_t=5f82kcndi6iqNSwqOVo5sd%2BHSoqhzQHKLGVs1HFegxx02UtWAA5gHQbWBfw&rqlang=cn&rsv_enter=0&rsv_dl=tb&rsv_sug3=24&rsv_sug1=14&rsv_sug7=100&rsv_btype=i&prefixsug=%25E5%25A6%2582%25E4%25BD%2595%25E6%25A6%259C%25E4%25B8%258A%25E5%25AF%258C%25E5%25A9%2586&rsp=4&inputT=8686&rsv_sug4=68370&rsv_jmp=fail"):
async with page.expect_navigation():
await page.click("text=百度一下")
# assert page.url == "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=%E5%A6%82%E4%BD%95%E6%A6%9C%E4%B8%8A%E5%AF%8C%E5%A9%86&fenlei=256&rsv_pq=ca59e3ec000cf6aa&rsv_t=5f82kcndi6iqNSwqOVo5sd%2BHSoqhzQHKLGVs1HFegxx02UtWAA5gHQbWBfw&rqlang=cn&rsv_enter=0&rsv_dl=tb&rsv_sug3=24&rsv_sug1=14&rsv_sug7=100&rsv_btype=i&prefixsug=%25E5%25A6%2582%25E4%25BD%2595%25E6%25A6%259C%25E4%25B8%258A%25E5%25AF%258C%25E5%25A9%2586&rsp=4&inputT=8686&rsv_sug4=68370"
# Close page
await page.close()
# ---------------------
await context.close()
await browser.close()
async def main() -> None:
async with async_playwright() as playwright:
await run(playwright)
asyncio.run(main())
可以看到這里的代碼和我們之前編寫的代碼基本類似曾棕,而且也是完全可以運(yùn)行的扣猫,運(yùn)行之后就可以看到它又復(fù)現(xiàn)了我們剛才的動(dòng)作。
另外這里的new_page并不是通過(guò)browser調(diào)用的翘地,而是通過(guò)context變量調(diào)用的申尤,context又是通過(guò)Browser對(duì)象調(diào)用的。這里的context變量相當(dāng)于一個(gè)BrowserContext對(duì)象衙耕,它是一個(gè)類似于隱身模式的獨(dú)立上下文環(huán)境昧穿,其運(yùn)行資源是隔離的,保證互不干擾橙喘。
選擇器
Playwright的文檔非常的豐富时鸵,可以直接參考https://playwright.dev/python/docs/selectors
事件監(jiān)聽
page對(duì)象提供了一個(gè)on方法,它可以用來(lái)監(jiān)聽頁(yè)面中各個(gè)事件厅瞎,比如close饰潜、console、load和簸、request彭雾、response等等。
比如我們可以監(jiān)聽response事件锁保,response事件可以在每次網(wǎng)絡(luò)請(qǐng)求得到響應(yīng)的時(shí)候觸發(fā)冠跷,我們可以設(shè)置對(duì)應(yīng)的回調(diào)方法獲取對(duì)應(yīng)的Response的全部信息。
from playwright.sync_api import sync_playwright
def on_response(response):
print(f'Statue {response.status}:{response.url}')
with sync_playwright() as p:
browser = p.chromium.launch(headless=False)
page = browser.new_page()
page.on('response', on_response)
page.goto('https://www.kenshujun.cn/')
page.wait_for_load_state('networkidle')
browser.close()
創(chuàng)建page對(duì)象之后身诺,就開始監(jiān)聽response事件蜜托,同時(shí)將回調(diào)方法設(shè)置為on_response撇寞,on_response對(duì)象接受一個(gè)參數(shù)四苇,然后把狀態(tài)碼和連接都輸出來(lái)。
看可以看到這里輸出的結(jié)果與瀏覽器Network面板所加載的內(nèi)容是一樣的颗管。