什么是 CDP
Chrome Devtools Protocol, 就是 Chrome 浏览器用于开发调试的协议,Chrome 开发者工具底层就是调用的该协议,所以 chrome 开发者工具能干的事都是基于 CDP 的接口,就能想到 CDP 能干的事有多少了。事实上 CDP 有些功能在 Chrome 开发者工具并没有体现出来,也就是说 CDP 还更强大。 简单来说,CDP 就是用来控制 Chrome 的方方面面。
事实上 CDP 能控制的并不局限于 Chrome 浏览器,任何实现了该协议的工具都能被控制。比如 Node.js, Firefox(没错,Firefox也实现了 CDP,但只能在 nightly 才能开启),还有所有基于 Chromium 内核的浏览器(360极速浏览器,Oper,edge,搜狗浏览器 等等)。
而任何实现了 CDP 的工具,都能使用 Chrome 开发者工具去调试与分析。所以 Chrome 开发者工具能调试 Node.js, Chromium 内核浏览器,甚至是 Firefox。
CDP 协议版本
CDP 有好几个版本,分别对应了不同的Chrome 版本或者不同端
-
latest 最新版,也叫 tip-of-tree (tot) ,这是个不稳定版本,API 随时可能会发生变化,而且还不保证向后兼容,但是它囊括了所有功能
-
v8-inspector ,这是给基于V8内核,比如 Node.js 6.3+ 就是基于该版本,用于调试和分析 nodejs 程序
-
stable 1.3 ,稳定版1.3,兼容 Chrome 64+ ,是 tot 版本的子集
-
stable 1.2 ,稳定版1.2,兼容 Chrome 54+ ,是 tot 版本的子集
体验 CDP
其实按F12打开 Chrome 开发工具就是最直接的体验了。在开发者工具能够实现的一切操作,直接使用CDP命令都可以实现,因为开发者工具底层调用的就是CDP命令。
我们可以验证这一说法,首先打开开发者工具设置中的实验功能,protocol monitor(协议监控)。
然后我们尝试使用开发者工具的一些功能,比如禁用断点。可以看到协议监控面板出现了Debugger.setBreakpointsActive命令,这就是一个CDP命令,我们也可以在CDP官网查询到这条命令。
那么这就是CDP协议的初步体验,接下来我们讲讲CDP的各个实现与应用。
启动 CDP 服务器
首先先启动 CDP 服务,这在实现了 CDP 的工具都会有说明,举例如下:
$ chrome --remote-debugging-port=9222 --remote-allow-origins=* # pc chrome $ adb forward tcp:9222 localabstract:chrome_devtools_remote # 安卓 chrome $ node --inspect=9222 script.js # Nodejs $ msedge --remote-debugging-port=9222 # 基于 Chromium 的新版 Edge $ firefox --remote-debugging-port 9222 # firefox nightly 浏览器
HTTP连接
CDP 服务的默认端口就是 9222
, 所以上面即使不指定端口号也是默认启动在 9222 端口上,这是个 http 服务。启动后可以浏览器直接访问 http://localhost:9222/json/version
一下试试(注意执行启动命令先关闭原来的浏览器)
这是CDP的一种连接方式,http
这里也标注一下json数据中键的含义:
-
id
: 会话 ID,用于在 CDP 中与特定页面进行通信。可以看到上面有两个不同id代表我开启了两个页面。 -
title
: 页面的标题。如上图,第一个标签页是bing。 -
url
: 当前页面的 URL。 -
webSocketDebuggerUrl
: WebSocket 地址,用于与 CDP 建立通信。没错这就是第二种与CDP通信的方式WebSocket。
WebSocket连接
我们以python为例,还是断点的例子,尝试把刚才禁用的断点启用。
import json
import websocket
# 从上面获取的webSocket连接地址
webSocketDebuggerUrl = "ws://localhost:9222/devtools/page/F5DA0B911ECE8584BAAAFB7911865216"
command = {
'method': 'Debugger.setBreakpointsActive',
'id': 123,
'params': {
'active': True,
}
}
connection = websocket.create_connection(webSocketDebuggerUrl)
connection.send(json.dumps(command))
print(json.loads(connection.recv()))
接收到响应。
那么利用CDP可以外部代码调试的特性,就可以开发很多的工具来进行浏览器操作自动化,爬虫等等。下面介绍CDP的应用。
CDP 开发
CDP 通常用作爬虫、自动化测试场景,所以你能在网上找到的资料,大部分都是讲 CDP 怎么开发爬虫和自动化测试。如果你要做爬虫或者自动化测试,可以先到 Awesome Chrome DevTools 先看看,看看有没有你使用的编程语言的实现。
Puppeteer
这是一个 nodejs 的包,封装了方方面面的高级 API 供使用,是做自动化测试和爬虫的首选工具。它还有其他编程语言的实现
-
Python port: pyppeteer
-
Rust port: Rust Headless Chrome
-
.NET port: Puppeteer Sharp
-
headless-devtools - Puppeteer plugin to get CSS Coverage or JS Heap snapshot.
-
PuPHPeteer - PHP-bridge to control Puppeteer using PHP.
怎么使用 puppeteer 教程很多,而我仅对他的实现感兴趣,这是一个非常好的学习 CDP 的项目,API 优雅,调试也简单,深入研究其原理后还可以自己实现一个。
注意有些项目早已停止维护,比如pyppeteer已经不随CDP协议更新而更新了,现在puppeteer仍然有活跃的开发者维护,支持一些最新的CDP特性。