Playwright是微软在2020年初开源的一款新一代自动化测试工具,其功能和**Selenium**、Pyppeteer类似,都可以驱动浏览器进行自动化操作,但是也具备了Selenium、Pyppeteer不具备的更好的API,是新一代爬取JavaScrip渲染页面的利器。
首先,确保python版本大于或等于3.7。
pip3 install playwright
安装完成后执行初始化操作。
playwright install
这是会自动安装Chromium、Firefox、WebKit浏览器和一些驱动。
Playwright支持两种编写模式,一种是和Pyppetter一样的异步模式,一种是和Selenium一样的同步模式,可以根据不同的实际需求来进行选择。
# 同步模式
# 调用了sync_playwright方法,该方法返回值是PlaywrightContext,可以理解为浏览器上下文管理器
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
for browser_type in [p.chromium,p.firefox,p.webkit]:
# 不把lauch的headless设置为False,默认为无头浏览器
browser = browser_type.launch(headless=False)
# 新建选项卡,返回page对象
page = browser.new_page()
page.goto('http://www.baidu.com/')
# 截图并定义文件名称
page.screenshot(path=f'screenshot-{browser_type.name}.png')
# title方法返回页面标题
print(page.title())
browser.close()
运行上面代码可以看到chromium、firefox、webkit三个浏览器依次启动,启动后加载百度首页,加载完成后生成截图,然后打印页面标题到控制台。
当然,除了同步模式,playwright还提供了支持异步模式的API,如果项目中使用了asyncio关键字,就应该使用异步模式。
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())
可以看到和同步模式基本一样,只不过导入方法改为async_playwright方法,不再是sync_playwright
方法,以及添加了async/await关键字,最后运行的效果是一样的。
(对于async和await关键字的使用可以参考,异步爬虫-协程的基本使用这篇文章。)
playwright还有一个强大的功能,那就是可以录制我们在浏览器当中的操作并且生成相对应的代码。这个功能可以通过playwright命令行调用codegen实现。比如输入以下命令:
playwright codegen --help
结果如下:
了解这些后我们可以尝试启动一个Firebox浏览器,然后将操作结果输出到script.py文件中。命令如下:
playwright codegen -o script.py -b firebox
运行后会弹出一个Firebox浏览器,右侧有个脚本窗口。
我们在弹出的浏览器打开百度,在搜索框输入nba,然后点击搜索,这时脚本窗口就会生成如下代码。而且我们可以看到会高亮显示我们正在操作的节点。
在我们操作浏览器的过程中,该窗口的代码会跟着实时变化。所有操作完毕后,关闭浏览器,playwright会生成目标文件,内容如下:
from playwright.sync_api import Playwright, sync_playwright, expect
def run(playwright: Playwright) -> None:
browser = playwright.firefox.launch(headless=False)
context = browser.new_context()
page = context.new_page()
page.goto("https://www.baidu.com/")
page.locator("#kw").fill("nba")
page.get_by_role("button", name="百度一下").click()
# ---------------------
context.close()
browser.close()
with sync_playwright() as playwright:
run(playwright)
由此可见,有了代码生成功能,只通过简单的可视化点击操作就能生成代码,可谓非常方便。
但是,观察生成的代码就会发现,这里的new_page不是通过browser调用的,而是通过context,这个context是由browser调用new_context方法生成的。这里context变量是一个BrowserContext对象,这是一个类似隐身模式的独立上下文环境,其运行资源是单独隔离的。在一些自动化测试中,我们可以为每个测试用例单独创建一个BrowserContext对象,这样可以保障各个测试用例之间互不干扰。
Playwright另一个特色就是可以支持模拟移动端浏览器,例如模拟打开iphone 13 Pro上的Safari浏览器。
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
iphone_13_pro = p.devices['iPhone 13 Pro']
browser = p.webkit.launch(headless=False)
context = browser.new_context(
**iphone_13_pro,
locale='zh-CN'
)
page = context.new_page()
page.goto('https://www.whatismybrowser.com/')
page.wait_for_load_state(state='networkidle')
page.screenshot(path='browser-iphone.png')
browser.close()
运行代码后我们就会发现,弹出一个浏览器窗口,然后加载出了对应页面。
这里我们先用PlaywrightContextManager对象的devices属性指定了一台移动设备,参数为设备的型号。
我们创建了一个移动端BrowserContext对象初始化一些设备的信息等,最后把返回的BrowserContext赋值给context变量。
接着,调用context的new_page方法创建一个新的选项卡,调动wait_for_load_state方法等待页面某个状态完成。netwoidle指网络空闲状态,即当前页面初始化和数据加载完成。
关于页面节点选择器得使用放在下个文章。
新一代爬取JavaScript渲染页面的利器-playwright(二)