crawl4ai智能爬虫(一):playwright爬虫框架详解
文章目录
- 一、playwright简介
- 1、任何浏览器 • 任何平台 • 一个 API
- 2、有弹性 • 没有碎片测试
- 3、无需权衡 • 无限制
- 4、完全隔离 • 快速执行
- 5、强大的工具
- 二、Playwright vs Selenium
- 三、playwright安装
- 四、API使用
- 1、同步和异步
- 2、关键对象
- 1)playwright
- 2)browser
- 3)page
- 3、爬虫关键步骤
- 4、元素定位
- 5、xpath定位
- 6、鼠标模拟
- 7、键盘输入
- 8、 js脚本执行:evaluate函数
- 9、记录脚本
- 10、反爬虫机制:UA隐匿
- 五、爬虫示例
- 六、参考链接
- 七、总结
一、playwright简介
crawl4ai 是专门为LLM设计的爬虫框架,底层使用playwright实现,本文介绍一下playwrigth爬虫框架。Playwright 是由 Microsoft 开发的一个开源自动化框架,主要用于测试和浏览器自动化。它的一个显著特点是支持 跨浏览器(Chromium、Firefox 和 WebKit)和跨平台(Windows、Linux 和 macOS)。对于爬虫开发者来说,它的价值在于能高效处理现代网页中常见的动态内容、JavaScript 渲染以及复杂的用户交互。
1、任何浏览器 • 任何平台 • 一个 API
跨浏览器。 Playwright 支持所有现代渲染引擎,包括 Chromium、WebKit 和 Firefox。
跨平台。 在 Windows、Linux 和 macOS 上进行本地或 CI 测试,无头或有头。
跨语言。 在 TypeScript、JavaScript、Python、.NET、Java 中使用 Playwright API。
测试移动网络。 适用于 Android 的 Google Chrome 和 Mobile Safari 的原生移动模拟。 相同的渲染引擎可以在桌面和云端运行。
2、有弹性 • 没有碎片测试
自动等待。 Playwright 在执行操作之前等待元素可操作。 它还具有丰富的内省事件。 两者的结合消除了人为超时的需要 - 这是造成碎片测试的主要原因。
网络优先的断言。 Playwright 断言是专门为动态网络创建的。 检查会自动重试,直到满足必要的条件。
追踪。 配置测试重试策略,捕获执行轨迹、视频、屏幕截图以消除碎片。
3、无需权衡 • 无限制
浏览器在不同的进程中运行属于不同来源的网页内容。 Playwright 与现代浏览器架构保持一致,并在进程外运行测试。 这使得 Playwright 摆脱了典型的进程内测试运行器限制。
多重一切。 跨越多个选项卡、多个来源和多个用户的测试场景。 为不同的用户创建具有不同上下文的场景,并在你的服务器上运行它们,所有这些都在一次测试中完成。
可信事件。 悬停元素、与动态控件交互、生成可信事件。 Playwright 使用与真实用户无法区分的真实浏览器输入管道。
测试框架,穿透 Shadow DOM。 Playwright 选择器穿透 Shadow DOM 并允许无缝进入帧。
4、完全隔离 • 快速执行
浏览器上下文。 Playwright 为每个测试创建一个浏览器上下文。 浏览器上下文相当于一个全新的浏览器配置文件。 这提供了零开销的全面测试隔离。 创建新的浏览器上下文只需几毫秒。
登录一次。 保存上下文的身份验证状态并在所有测试中重用它。 这绕过了每个测试中的重复登录操作,但提供了独立测试的完全隔离。
5、强大的工具
代码生成。 通过记录你的操作来生成测试。 将它们保存为任何语言。
Playwright 检查器。 检查页面、生成选择器、逐步执行测试、查看点击点、探索执行日志。
跟踪查看器。 捕获所有信息以调查测试失败。 Playwright 跟踪包含测试执行截屏、实时 DOM 快照、动作资源管理器、测试源等等。
二、Playwright vs Selenium
playwright和selenium都是网页自动化测试框架,Playwright 相较于 Selenium 的主要优势包括:
无需 WebDriver:直接通过开发者工具与浏览器交互,安装更简洁。
自动等待:无需手动添加 sleep,Playwright 会自动等待元素加载。
多语言支持:支持 Python、JavaScript 等多种语言。
双向通信:基于 WebSocket,可实时获取浏览器状态。
- Selenium 更像是"老牌全能选手",历史悠久、生态庞大。
- Playwright 更像是"年轻小钢炮",速度快,支持现代网页特性,API 也更友好。
特点 | Selenium | Playwright |
---|---|---|
诞生时间 | 2004 年,历史悠久 | 2020 年,后起之秀 |
浏览器支持 | Chrome, Firefox, Safari, IE 等 | Chromium, Firefox, WebKit(现代浏览器全覆盖) |
API 设计 | 早期接口多,稍显复杂 | API 简洁现代,学习成本低 |
执行速度 | 较慢,常遇到等待问题 | 更快,更少超时 |
特殊功能 | 较强大,生态成熟 | 原生支持截图、录制视频、Mock 网络请求 |
下表对比了 Playwright 和 Selenium 这两个流行的自动化工具在爬虫应用中的关键差异,理解为何 Playwright 在现代 Web 爬虫中更受青睐。
特性对比 | Playwright | Selenium |
---|---|---|
架构与通信 | 基于 WebSocket 和 DevTools 协议 直接与浏览器内核通信,无需额外驱动,通信效率高。 | 通过 WebDriver 协议 经 HTTP/JSON 与浏览器驱动通信,存在中间层,速度相对较慢。 |
执行速度 | 通常更快,在无头模式下可比 Selenium 快 30%-50%。 | 相对较慢。 |
浏览器管理 | 开箱即用,自带浏览器内核,版本自动匹配,无需单独管理驱动。 | 需手动下载和匹配特定版本的浏览器驱动,维护更繁琐。 |
等待机制 | 自动等待 元素可交互(如点击、输入),减少手动等待代码,稳定性更高。 | 通常需要开发者手动设置显式或隐式等待,代码更复杂且易因等待时间设置不当失败。 |
移动端模拟 | 原生支持移动设备参数库,可精准模拟触屏手势等。 | 主要通过 ChromeOptions 模拟分辨率,功能有限。 |
网络拦截 | 内置强大 API,可直接修改请求头、模拟慢速网络等。 | 需要借助 BrowserMob Proxy 等第三方工具。 |
三、playwright安装
1)安装python库:
pip install playwright
2)安装浏览器
playwright install
or
python -m playwright install # 仅安装 Chromium, 指定浏览器
python -m playwright install chromium
注意Playwright 需要 Python 3.7 或更高版本。
四、API使用
1、同步和异步
- 同步方法
from playwright.sync_api import sync_playwright
with sync_playwright() as p:# 启动浏览器browser = p.chromium.launch(headless=False)page = browser.new_page()# 打开网页page.goto("https://www.baidu.com/")# 截取屏幕截图page.screenshot(path="example.png")# 关闭浏览器browser.close()
- 异步方法
需要使用asyncio库。async 是定义协程,await 用于挂起协程以等待耗时操作完成。
import asyncio
from playwright.async_api import async_playwright
async def main():async with async_playwright() as p:browser = await p.chromium.launch(headless=False)page = await browser.new_page()await page.goto("https://www.baidu.com/")await page.screenshot(path="example.png")await browser.close()
asyncio.run(main())
- asyncio
这里简单介绍一下asyncio的使用,asyncio.gather 起两个协程处理。asyncio.run() 自动管理事件循环,以及触发协程异步执行。
import asyncio
async def task(name, delay):print(f"Task {name} started")await asyncio.sleep(delay)print(f"Task {name} finished")
async def main():await asyncio.gather(task("A", 2),task("B", 3))
asyncio.run(main())
asyncio.run 等效如下:
import asyncio
async def hello():print("Hello")await asyncio.sleep(1)print("World")
loop = asyncio.get_event_loop()
loop.run_until_complete(hello())
loop.close()
2、关键对象
playwright爬虫3个关键对象:playwright、browser、page。
1)playwright
全局控制对象,有sync_playwright和async_playwright两个api版本,浏览器对象是由playwright对象启动的。
from playwright.async_api import async_playwright
2)browser
浏览器对象,由playwright启动browser_type.launch()创建一个browser对象,可以选择不同的浏览器
3)page
page是一个标签页,先创建一个标签页,然后使用goto方法跳转到对应网页页面,而selenium中的page是浏览器get后获取的内容,两者概念不一样。
browser.new_page()
browser和page都是和selenium一样的概念,这里多了一个playwright对象来启动browser,3个关键对象的对应关系。
类 | playwright | selenium |
---|---|---|
全局控制 | playwright | webdriver |
浏览器对象 | browser | driver: webdriver.Chrome ,每个浏览器都有特定方法。 |
标签窗口 | page | window |
如下代码示例,以同步方法理清3个对象的层级关系。
playwright版本:
from playwright.sync_api import sync_playwright, Playwrightdef run(playwright: Playwright):firefox = playwright.firefoxbrowser = firefox.launch()page = browser.new_page()page.goto("https://example.com")browser.close()with sync_playwright() as playwright:run(playwright)
对比selenium版本代码示例:
from selenium import webdriver
import time
option = webdriver.ChromeOptions()
option.add_experimental_option("detach", True)# Chrome浏览器
driver = webdriver.Chrome(chrome_options=option)
# driver.set_window_size(500, 500)
# 设置窗口大小
driver.maximize_window()
driver.get('https://www.csdn.net/')# 定位页面元素
app = driver.find_element_by_id("app")
print(dir(app))print(app.text)
print("=======home warp=======")
# 是个对象
home_wrap = driver.find_element_by_class_name("home_wrap")
print(home_wrap.text)# back and forword
#time.sleep(2)
#driver.get("https://blog.csdn.net/ruguowoshiyu/article/details/80539299")
#time.sleep(2)
#driver.back()
#time.sleep(3)
#driver.forward()
#time.sleep(3)
#print(dir(driver))# 新的页面打开窗口,执行js脚本
js = "window.open('https://blog.csdn.net/qq_43965708')"
driver.execute_script(js)# 等待加载完成
time.sleep(3)
print("refresh")
driver.refresh()
time.sleep(3)# 前后窗口切换
windows = driver.window_handles
driver.switch_to.window(windows[0])
time.sleep(3)
# 最后一个窗口
driver.switch_to.window(windows[-1])
time.sleep(3)# 退出浏览器
driver.quit()
3、爬虫关键步骤
详细的API文档官方文档已经介绍很清楚,这里只针对爬虫常见的API做介绍,看一下爬虫常规的步骤:
1)根据url抓取page的html内容
2)解析html,定位某些元素内容,(保存数据or新的url继续爬取子page)
3)鼠标点击和键盘输入,比如登录等功能
4)反爬机制:设置UA代理等。
- 获取html文本
page.content()
- 截图功能
page.screenshot(path="example.png")
- 录制视频
context = browser.new_context(record_video_dir="videos/")
# Make sure to close, so that videos are saved.
context.close()
4、元素定位
Locator 定位器代表了一种随时在页面上查找元素的方法,可以使用 page.locator() 方法创建定位器。如get_by_role返回的就是一个定位器,定位器元素可以执行click函数进行点击。
for li in page.get_by_role('listitem').all():li.click();
定位器的文本信息获取:
texts = page.get_by_role("link").all_text_contents()
texts = page.get_by_role("link").all_inner_texts()
page提供了一些定位方法,比如:
- get_by_alt_text
通过替代文本alt文本定位图片,然后执行click()方法。
<img alt='Playwright logo'>
page.get_by_alt_text("Playwright logo").click()
- get_by_role
根据type类型和name来定位元素。
<h3>Sign up</h3>
<label><input type="checkbox" /> Subscribe
</label>
<br/>
<button>Submit</button>
expect(page.get_by_role("heading", name="Sign up")).to_be_visible()page.get_by_role("checkbox", name="Subscribe").check()page.get_by_role("button", name=re.compile("submit", re.IGNORECASE)).click()
- get_by_text
<div>Hello <span>world</span></div>
<div>Hello</div>
匹配
# Matches <span>
page.get_by_text("world")# Matches first <div>
page.get_by_text("Hello world")# Matches second <div>
page.get_by_text("Hello", exact=True)# Matches both <div>s
page.get_by_text(re.compile("Hello"))# Matches second <div>
page.get_by_text(re.compile("^hello$", re.IGNORECASE))
- get_by_title
<span title='Issues count'>25 issues</span>
expect(page.get_by_title("Issues count")).to_have_text("25 issues")
5、xpath定位
特性 | 说明 | 示例 |
---|---|---|
显式写法 | 在表达式前加上 xpath= 前缀,明确指定定位策略。 | page.locator("xpath=//button[@id='submit']") |
隐式写法 | 当表达式以 // 或 .// 等XPath特有语法开头时,可省略前缀,Playwright会自动识别。 | page.locator("//button[@id='submit']") |
表达式规范 | XPath 表达式通常需要以 // 开头,表示从根节点或任意位置开始匹配。 | //input[@id='username'] |
文本匹配 | 支持使用 text() , contains() , starts-with() 等函数进行复杂的文本或属性匹配。 | //a[text()='Sign In'] //div[contains(@class, 'error')] |
6、鼠标模拟
- click方法
点击某个位置。
mouse.click(x, y)
mouse.click(x, y, **kwargs)
- 双击
mouse.dblclick(x, y)
mouse.dblclick(x, y, **kwargs)
- 滚动 wheel
mouse.wheel(delta_x, delta_y)
7、键盘输入
- 输入字符
page.keyboard.insert_text("嗨")
- 按键事件keyboard.press 相当与down()+up()。
page = browser.new_page()
page.goto("https://keycode.info")
page.keyboard.press("a")
page.screenshot(path="a.png")
page.keyboard.press("ArrowLeft")
page.screenshot(path="arrow_left.png")
page.keyboard.press("Shift+O")
page.screenshot(path="o.png")
browser.close()
8、 js脚本执行:evaluate函数
# 获取浏览器语言
lan = page.evaluate("window.navigator.language;")
print(lan)
9、记录脚本
playwright codegen命令用于录制脚本,target参数 选择脚本语言类型。比如:
playwright codegen --target python -o test_script.py https://www.baidu.com/
10、反爬虫机制:UA隐匿
有时爬虫需要设置UA代理,模拟浏览器行为,可以构造UA代理,比如如下代码:
from playwright.sync_api import sync_playwright
with sync_playwright() as playwright:browser = playwright.chromium.launch(headless=False)page = browser.new_page(user_agent='Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36')page.goto("https://www.baidu.com/")page.wait_for_timeout(10000)browser.close()
五、爬虫示例
比如爬取csdn网站哪,获取csdn的某个文章的title信息
<h1 class="title-article" id="articleContentId">如何快速学习一个网络协议?</h1>
使用xpath获取文章的title信息,代码示例如下:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:# 启动浏览器browser = p.chromium.launch(headless=False)page = browser.new_page()print(dir(page))# 打开网页page.goto("https://blog.csdn.net/qq_40036519/article/details/152513893")# 截取屏幕截图# page.screenshot(path="example.png")html = page.content()print(html)lan = page.evaluate("window.navigator.language;")print(lan)title=page.locator("//h1[@id='articleContentId']")for ti in title.all_inner_texts():print(ti)# 关闭浏览器browser.close()
六、参考链接
- Playwright 官网
- Playwright 开源地址
- Playwright API 文档
- playwright中文网
-
菜鸟教程
-
selenium 官方文档
七、总结
总的来说,Playwright 凭借其现代的设计、卓越的性能和开发者友好的 API,非常适合用于构建高效、稳定的爬虫系统,尤其是在应对复杂动态网站时优势明显。