一、Playwright简介
微软开发,基于Chrome 开发者工具协议(Chrome DevTools Protocol,简称CDP)的浏览器自动化工具。
优点:
- 不需要浏览器驱动
- 速度比较快、天生支持异步
- 几乎可以自动化浏览器的全部功能
- 定位比较方便
- 很好和AI结合(MCP、SKILL高级支持)
缺点:
- 支持浏览器比较有限:主要是Chrome、Chromeium
二、安装Playwright
官网:playwright.dev/python/docs...
python
pip install pytest-playwright
playwright install chromium #playwright默认使用这里安装的浏览器,而不是用户自己安装的chrome
三、录制脚本
python
playwright codegen https://www.sogou.com/
执行后会自动打开浏览器并跳转搜狗搜索的网页。搜索今日黄金价格,Playwright会将搜索操作录制成脚本。如何断言呢?可以按照下图点击完"1"后,点击"2",将"2"中的内容作为断言条件,也可以在"3"中修改断言条件,最后点"4"将断言操作记录到录制脚本中。

录制好的脚本在这个窗口:

四、Playwright对浏览器的常用操作
这部分是固定内容
python
from playwright.sync_api import Playwright, sync_playwright, expect
def run(playwright: Playwright) -> None:
browser = playwright.chromium.launch(headless=False) #启动浏览器,返回 Browser 类型对象,使用有头模式
context = browser.new_context() #创建 BrowserContext对象
page = context.new_page() #创建新页面,返回 Page 类型对象
page.goto("https://www.sogou.com/")
...
context.close()
browser.close()
with sync_playwright() as playwright:
run(playwright)
1、页面导航
python
page.goto("https://www.sogou.com/") #跳转url
page.reload() #刷新
page.go_back() #后退
page.go_forward() #前进
2、页面内容
python
print("title:",page.title()) #网页标题(HTML中的title)
print("url:",page.url) #当前网页地址
print("content:",page.content()) #当前网页内容(完整HTML)
3、页面动作
python
page.set_viewport_size({"width":1080,"height":300}) #设置窗口大小
page.mouse.wheel() #页面滚动
page.expect_dialog() #弹窗处理
page.screenshot(path="1.png") #页面截图
page.evaluate('location.href="https://qq.com"') #执行js代码
#执行js代码,从浏览器内部进行自动化,这里的操作是通过js代码跳转到腾讯网页。例如一些场景不便从外部进行自动化们可以通过js代码从浏览器内部执行一些自动化操作
4、元素内容
python
.inner_text() 获取可见文本
.input_value() 获取输入框值
.get_attribute() 获取元素属性
.count() 获取匹配元素个数
5、元素动作
python
.fill() 输入内容
.click() 点击
.press() 按键(Enter/Tab)
.check() 勾选复选框
.select_option() 下拉选择
.set_input_files() 文件上传
6、断言
页面断言
python
expect(page).to_have_url() 校验 URL
expect(page).to_have_title() 校验标题
元素断言
python
expect(locator).to_be_visible() 元素可见
expect(locator).to_contain_text() 包含文本
expect(locator).to_have_text() 文本完全匹配
expect(locator).to_have_value() 输入框值校验
expect(locator).to_be_enabled() 元素可用
五、Playwright元素定位
Selenium经典的八大元素定位,Selenium把这 8 种作为独立、平级的定位类型:id | name | class name | link name(完整链接文本) | partial link text(部分链接文本) | tag name(标签名,如 input/div) | css selector | xpath
Playwright 底层只有两大类选择器:CSS、XPath。像 id/name/class/tag,本质都属于 CSS 选择器;link 文本定位是 Playwright 内置的文本选择器语法,并不是独立底层类型。
固定内容:
python
from playwright.sync_api import Playwright, sync_playwright, expect
def run(playwright: Playwright) -> None:
browser = playwright.chromium.launch(headless=False) #启动浏览器,返回 Browser 类型对象,使用有头模式
context = browser.new_context() #创建 BrowserContext对象
page = context.new_page() #创建新页面,返回 Page 类型对象
page.goto("https://www.bilibili.com/?spm_id_from=333.1387.0.0")
##Playwright底层使用的是异步的python库进行各种事件处理,time.sleep 会破坏异步框架的处理逻辑。可以使用Page对象的wait_for_timeout方法达到等待效果,单位是 毫秒
page.wait_for_timeout(1000) # 等待1秒,确保页面加载完成
...
context.close()
browser.close()
with sync_playwright() as playwright:
run(playwright)
1、XPATH元素定位
- / 从根节点选取
- // 从非根节点选取
- * 任意节点选取
- @ 根据属性筛选
- text() 根据文本筛选
- and 关联属性或者链接文本
- \[\] 可以放置下标/属性/链接文本
- . 选取当前节点
- .. 选取当前节点的父节点
- contains 包含

python
#单一属性定位-->设置
text1 = page.locator('//span[@name="tj_settingicon"]').inner_text()
print(text1)
#多属性定位-->设置
text2 = page.locator('//span[@name="tj_settingicon" and @id="s-usersetting-top"]').inner_text()
print(text2)
#父节点定位-->设置
text3=page.locator('//div[@id="u1"]/span').inner_text()
print(text3)

python
#通过下标定位-->新闻
text4=page.locator('//a[@class="mnav c-font-normal c-color-t"][1]').inner_text() #直接使用下标,"新闻"是1,"hao123"是2,以此类推
text4=page.locator('//div[@class="s-top-tabs"]/a[1]').inner_text() #通过父节点+下标方式

python
#通过.和..定位
text5=page.locator('//a[@name="tjfanyi"]/div/../../../../a').inner_text() #通过"翻译"定位到"更多"按钮
print(text5)

python
#通过文本定位
text6=page.locator('//a[text()="更多"]').inner_text()
print(text6)
#通过模糊匹配
text7=page.locator('//a[contains(text(), "hao")]').inner_text()
print(text7)
总结:
- 尽量不要使用绝对路径
- 尽量减少路径级别
- 尽量不要使用下标
- 尽量使用最简洁的写法
2、CSS元素定位
- id选择器
- class选择器
- 元素选择器
- 属性选择器
- 层级选择器

python
#id属性定位,id=可以简写为#
page.locator('#query').fill('id属性')
#name属性定位,name没有简写,只能用方括号定位
page.locator('[name="query"]').fill('name属性定位')
#class属性定位
page.locator('.sec-input').fill('class属性')
#标签+属性定位
page.locator('input#query').fill('标签+id属性定位')
#层级关系定位
page.locator('div>form>span>input.sec-input').fill('层级关系定位')