第 2 课
开 CDP 服务,接 Puppeteer、Playwright 和 Python
用 lightpanda serve 在 9222 端口开 CDP 服务并用 /json/version 检查,用 puppeteer.connect 和 chromium.connectOverCDP 连接抓取名言,用 /metrics 看连接与命令数,再用官方 Python 包和 extract 选择器表沿 Next 链接抓完 100 条名言并统计标签。
课程目录第 2 / 3 课
学习位置仅保存在当前浏览器,有效期 180 天。
图文教材
本课对照的官方页面:Puppeteer / Playwright 快速开始、Puppeteer 用法、Playwright 用法、serve 参数、Python 包。命令与输出在 Linux x86_64 云主机上实测(Lightpanda 1.0.2、Node.js 20.19.2、puppeteer-core 24.43.1、playwright-core 1.64.1、Python 3.13.5、lightpanda 包 1.0.2),输出为节选。
上一课的 fetch 一次只处理一个页面。要点击、输入、翻页,就需要脚本来驱动浏览器。这一课让 Lightpanda 开一个 CDP 服务,用 Puppeteer、Playwright 连上去,再用官方 Python 包抓 10 页数据。
第 1 步:开 CDP 服务
CDP 是 Chrome DevTools Protocol,Puppeteer 和 Playwright 都用它控制 Chrome。Lightpanda 实现了同一套协议,所以这些库不用改就能连上它。开一个终端运行:
export LIGHTPANDA_DISABLE_TELEMETRY=true
lightpanda serve --host 127.0.0.1 --port 9222
对照结果:
$scope=note $level=note $msg="server running" address=127.0.0.1:9222
max_connections=16208 max_browser_connections=16
这个终端保持运行。再开一个终端,确认服务正常:
curl -s http://127.0.0.1:9222/json/version
对照结果:
{"Browser": "Lightpanda/1.0", "Protocol-Version": "1.3",
"User-Agent": "Lightpanda/1.0", "Lightpanda-Version": "1.0.2",
"webSocketDebuggerUrl": "ws://127.0.0.1:9222/"}
webSocketDebuggerUrl 就是下面脚本要连的地址。默认最多同时接 16 个 CDP 连接,可用 --cdp-max-connections 调整。--host 默认是 127.0.0.1,只有本机能连。改成 0.0.0.0 会让同一网络里的任何人都能操控这个浏览器,不要在公网机器上这样开。
第 2 步:用 Puppeteer 连接
新建项目目录,装 puppeteer-core。它和 puppeteer 的区别是不会下载 Chromium:
mkdir lp-quickstart && cd lp-quickstart
npm init -y
npm pkg set type=module
npm install --save puppeteer-core playwright-core
新建 pptr.mjs。关键是用 puppeteer.connect 连已有的浏览器,而不是用 launch 启动 Chrome:
import puppeteer from 'puppeteer-core';
const browser = await puppeteer.connect({
browserWSEndpoint: 'ws://127.0.0.1:9222',
});
const context = await browser.createBrowserContext();
const page = await context.newPage();
await page.goto('https://quotes.toscrape.com/js/', {
waitUntil: 'networkidle0',
});
const quotes = await page.$$eval('.quote', (els) =>
els.slice(0, 3).map((el) => ({
text: el.querySelector('.text').textContent,
author: el.querySelector('.author').textContent,
})),
);
console.log(await page.title());
console.log(quotes);
await page.close();
await context.close();
await browser.disconnect();
运行:
node pptr.mjs
对照结果(名言文字有删节):
Quotes to Scrape
[
{ text: '“The world as we have created it is a process of our ...”',
author: 'Albert Einstein' },
{ text: '“It is our choices, Harry, that show what we truly are, ...”',
author: 'J.K. Rowling' },
{ text: '“There are only two ways to live your life. ...”',
author: 'Albert Einstein' }
]
测试机上整个脚本约 2 秒跑完。注意最后用的是 browser.disconnect() 而不是 close():浏览器是 serve 启动的,脚本只负责断开连接。
第 3 步:用 Playwright 连接
Playwright 用 chromium.connectOverCDP 连接。在同一目录新建 pw.mjs:
import { chromium } from 'playwright-core';
const browser = await chromium.connectOverCDP('ws://127.0.0.1:9222');
const context = await browser.newContext();
const page = await context.newPage();
await page.goto('https://quotes.toscrape.com/js/');
await page.waitForSelector('.quote');
const n = await page.locator('.quote').count();
const first = await page.locator('.quote .author').first().textContent();
console.log({ count: n, firstAuthor: first });
await page.close();
await context.close();
await browser.close();
运行:
node pw.mjs
对照结果:
{ count: 10, firstAuthor: 'Albert Einstein' }
Python 版 Playwright 写法相同,官方安装命令是 pip install playwright,连接时用 p.chromium.connect_over_cdp("ws://127.0.0.1:9222")。官方步骤里只有这一条安装命令,没有用 playwright install 下载浏览器(本课没有实跑 Python 版 Playwright,这段未实测)。
两个脚本都跑完后,可以看看服务端的统计。serve 默认提供 Prometheus 格式的 /metrics 接口:
curl -s http://127.0.0.1:9222/metrics |
grep -E '^serve_(connections|commands)_total\{driver="cdp"\}'
对照结果:
serve_connections_total{driver="cdp"} 2
serve_commands_total{driver="cdp"} 138
两个脚本一共发了 138 条 CDP 命令。不需要这个接口时,启动时加 --disable-metrics 关掉。练习完回到第一个终端按 Ctrl+C 停掉服务。
第 4 步:用官方 Python 包抓 10 页数据
Lightpanda 还有官方 Python 包 lightpanda。它自带浏览器二进制文件,不用单独开 serve,也不用装 Playwright。要求 Python 3.10 及以上:
python3 -m venv .venv
. .venv/bin/activate
pip install lightpanda
新建 scrape.py,沿着页面上的 Next 链接把 10 页名言全部抓下来,再统计标签。代码来自官方指南:
from collections import Counter
from lightpanda import Browser
SCHEMA = {
"quotes": [
{
"selector": ".quote",
"fields": {
"text": ".text",
"author": ".author",
"tags": [".tag"],
},
}
],
"next": {"selector": "li.next a", "attr": "href"},
}
with Browser() as browser, browser.new_session() as page:
quotes = []
url = "https://quotes.toscrape.com/js/"
while url:
page.goto(url=url)
data = page.extract(schema=SCHEMA)
quotes.extend(data["quotes"])
url = data["next"]
print(f"{len(quotes)} quotes")
tags = Counter(tag for q in quotes for tag in q["tags"])
print("Top tags:", tags.most_common(5))
运行:
python scrape.py
对照结果(与官方文档给出的结果一致):
100 quotes
Top tags: [('love', 14), ('inspirational', 13), ('life', 13),
('humor', 12), ('books', 11)]
(第二行是排版折行。)
测试机上 10 页约 6 秒跑完。extract 用的选择器表(schema)规则如下:
- 字符串
".text":取第一个匹配元素的文字 {"selector": ..., "attr": "href"}:取第一个匹配元素的属性,链接会补全成完整网址[".tag"]:取所有匹配元素的文字,得到列表[{"selector": ".quote", "fields": {...}}]:每个匹配元素生成一条记录,fields里的选择器在这个元素内部查找
最后一页没有 Next 链接,data["next"] 是 None,循环自然结束。
第 5 步:了解其他连接方式(未实测)
本课没有实跑下面两种方式,按官方文档列出,需要时再查:
- Selenium:
lightpanda serve --protocol webdriver提供 WebDriver BiDi 和经典 WebDriver 接口,见 https://lightpanda.io/docs/usage/bidi/selenium - Lightpanda Cloud:把连接地址换成
wss://euwest.cloud.lightpanda.io/ws?token=你的令牌(另有uswest区域),需要在官网注册拿令牌,见 https://lightpanda.io/docs/usage/cdp/puppeteer
Lightpanda 没有图形渲染,官方文档说明它的截图只是按文字排版画出来的,没有图片、字体和 CSS 颜色,需要像素级截图的任务仍要用 Chrome。官方云服务支持用 browser=chrome 参数换成 Chrome 实例。
小结
lightpanda serve默认在127.0.0.1:9222开 CDP 服务,/json/version可用来检查服务是否正常- Puppeteer 用
puppeteer.connect({ browserWSEndpoint }),Playwright 用chromium.connectOverCDP,装-core版本就够了 - 脚本结束时 Puppeteer 用
disconnect(),浏览器进程交给serve管理 /metrics能看到连接数和命令数,--disable-metrics可以关闭- 官方 Python 包自带浏览器,
page.extract加选择器表就能抓结构化数据
下一课把 Lightpanda 作为 MCP 服务器交给 AI 应用,让大模型自己操作浏览器。
