尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

cdp 方式的 python 爬虫

cdp 方式的 python 爬虫 ​devtools-protocolhttps://github.com/ChromeDevTools/devtools-protocolChrome DevTools Protocolhttps://chromedevtools.github.io/devtools-protocol/cdp chromehttps://github.com/search?qcdpchrometyperepositoriespypi 搜索 playwrighthttps://pypi.org/search/?qplaywrightpypi 搜索cdp、playwright、chrome1、关于 cdpcdp 简介CDP ( Chrome Debugging Protocol ) 就是 Chrome 调试协议通过 WebSocket 直接控制 Chrome/Chromium不需要 chromedriver 驱动可以渲染 JS、抓接口请求、拦截请求、执行 JS、获取 cookie、截图适合 SPA、加密接口、反爬站点。Chrome 提供了 websocket 调试接口可以对当前 Tab 内页面的 DOM、网络、性能、存储 等等进行调试开发者工具就是基于此接口这个接口也支持远程调用在启动参数中加上--remote-debugging-port9222即可。基于 cdp 封装的库目前已经有很多大神针对这个协议封装出不同语言nodejspythonjava...的库。awesome-chrome-devtoolshttps://github.com/ChromeDevTools/awesome-chrome-devtoolsJavaScript/Node.js: chrome-remote-interfaceTypeScript/Node.js: chrome-debugging-clientTypeScript/Node.js: noice-json-rpc - A proxy-based implementation to expose the CDP as its API.TypeScript/Node.js: TaikoTypeScript/Node.js: Lumen - Vision-first browser agent with self-healing deterministic replay over CDP.Rust: Rust Headless ChromeJava: chrome-devtools-java-clientJava: jvppeteer - Headless Chrome For JavaPython: PyCDP - Pure-Python, sans-IO wrappers. See also the Trio CDP driverPython: chromewhip - drop-in replacement for thesplashservicePython: pyppeteer - Puppeteer portPython: ChromeController - high-level browser mgmtGo: chromedp - High-level actions and tasks for driving browsersGo: cdpGo: gcdGo: godetGo: RodC#/.NET: Puppeteer Sharp - Puppeteer portC#/dotnet: chrome-dev-tools - Protocol wrapper generator that can be customized by editing handlebars templates. Includes .Net Core template.C#/.NET: dotnet-chrome-protocol - A runtime library and schema code generation tools for Chrome DevTools Protocol support in C#/.NET.Ruby: Ferrum - high-level API to control Chrome in RubyRuby: Cuprite - Capybara driverKotlin: chrome-reactive-kotlin - reactive (rxjava 2.x), low-level client library in KotlinKotlin: chrome-devtools-kotlin - A coroutine-based client library, providing low-level CDP primitives and high-level extensions.Clojure: clj-chrome-devtools - The CDP wrapper API is autogenerated and will be updated when CDP protocol changes.Clojure: cuic - Providing a high-level API for UI test automation over the DevTools Protocol.PHP: chrome-devtools-protocol - A PHP client library for the protocol.PHP: PuPHPeteer - PHP bridge to node Puppeteer开启 chrome 远程调试远程调试接口是一个 WebSocket 的接口Chrome 内置的开发者工具是一种客户端自己写代码调用也是一种客户端。DevTools 可以 attach 到一个远程的 Chrome 实例从而进行远程 debug。关闭全部 Chrome 窗口命令行启动 Chrome 开启9222调试端口。# Linux/Mac google-chrome --remote-debugging-port9222 --user-data-dir./chrome_profile # Windows C:\Program Files\Google\Chrome\Application\chrome.exe --remote-debugging-port9222 --user-data-dirD:\chrome_profile启动一个 Chrome 实例chrome.exe --remote-debugging-port9222指定用户配置文件启动一个 Chrome 实例 chrome.exe --user-data-dirsome directory 。--user-data-dir独立用户目录保存 cookie、登录态可以复用你登录好的浏览器。 访问http://127.0.0.1:9222/json/list可以拿到各个 tab 的 websocket 地址。在客户端中输入http://localhost:9222就会看到当前 client 端的 DevTools 就像内嵌在电脑中Chrome 的 devtools 一样然后你就可以通过 client 操作他了。当用 client 连接到 9222 的时候DevTools 前端 会被 host Chrome 实例 serve 为一个远程服务端的 web application他会通过 HTTP 协议 fetch HTMLJavaScriptCSS一旦加载DevTools 会和 host 建立一个 ws 链接并开始交换 JSON 信息也可以用自己的实现来替代 DevTools 前端除了localhost:9222远程调试还提供了一个JSON接口用于管理浏览器的 Tab 页面。localhost:9222/json来获取到 ws 通信的 JSONobject并修改使用它们 HTTP Endpoints 章节中有详细内容。 Playwright、Pyppeteer 底层就是封装 CDP也可以直接裸写 WebSocket 调用原始 CDP 指令。库特点适用场景ichromeasync轻量 CDP 封装国内常用直接操作 CDP抓包爬虫推荐学习博客园pyppeteerPython 版 puppeteer高层封装 CDP简单爬虫不再维护playwright高层封装chromium 底层走 CDP业务爬虫生产首选不用手写 CDP 报文cdpred / cdp‑toolkit极简原始 CDP 客户端直接发 CDP 命令需要底层精细控制 ChromePyPIwebsocket‑client裸 WebSocket自己组装 CDP json 报文研究协议不推荐业务开发大多数爬虫业务优先Playwright需要直接调用原生 CDP 命令选ichrome。本地浏览器开http://服务器IP:9222/json 本机测试的话就是 http://127.0.0.1:9222/json这里列出了当前远程浏览器内打开的Tab每个页面一个UUID用以识别。已知接口http://127.0.0.1:9222/json 查看已经打开的Tab列表http://127.0.0.1:9222/json/version : 查看浏览器版本信息http://127.0.0.1:9222/json/new?http://www.baidu.com : 新开Tab打开指定地址http://127.0.0.1:9222/json/close/ac5a6adb-bb53-44f1-a9e6-2354bd724924 : 关闭指定Tabhttp://127.0.0.1:9222/json/activate/69301801-d503-42a3-9335-3e448a780857 : 切换到目标Tab示例 1ichrome 直接 CDP安装pip install ichromeimport asyncio from ichrome import AsyncChrome async def main(): # 连接已经启动好的chrome:9222 chrome AsyncChrome(host127.0.0.1, port9222) if not await chrome.connect(): raise Exception(Chrome CDP连接失败请先启动chrome调试端口) tab await chrome.new_tab() async with tab: # 访问网页 await tab.set_url(https://httpbin.org/html, timeout10) # 执行JS获取页面标题 title await tab.js(document.title) print(页面标题, title) # 获取完整html html await tab.js(document.documentElement.outerHTML) print(html[:300]) # CDP原生命令截图 screenshot await tab.send(Page.captureScreenshot) with open(screenshot.png, wb) as f: f.write(screenshot[data]) await tab.close() await chrome.close() if __name__ __main__: asyncio.run(main())CDP 抓网络请求监听接口返回 JSONasync def capture_network(tab): await tab.send(Network.enable) # 监听responseReceived事件 def on_response(event): resp event[params][response] url resp[url] if /api/ in url: print(f捕获接口:{url} status{resp[status]}) tab.on(Network.responseReceived, on_response)示例 2Playwright 调用 CDPPlaywright 调用原生 CDP 命令生产最常用。因为 Playwright 封装了浏览器同时支持直接执行底层 CDP 指令不需要手动启动 chrome自动管理浏览器进程。pip install playwright playwright install chromiumfrom playwright.async_api import async_playwright import asyncio async def main(): async with async_playwright() as p: browser await p.chromium.launch(headlessFalse) page await browser.new_page() # 【直接调用CDP原生命令】 client await page.context().new_cdp_session(page) await client.send(Network.enable) # 监听网络响应CDP事件 async def handle_response(event): res event[params][response] if api in res[url]: print(res[url], res[status]) client.on(Network.responseReceived, handle_response) await page.goto(https://httpbin.org) print(await page.title()) # CDP截图命令 await client.send(Page.captureScreenshot, {format:png}) await browser.close() asyncio.run(main())如果本地已经手动启动带 9222 端口的 Chrome可以让 playwright 连接已有浏览器browser await p.chromium.connect_over_cdp(http://127.0.0.1:9222)示例 3裸 WebSocket 原始 CDP这个主要用来理解协议原理pip install websocket-client requestsimport json import requests import websocket # 获取tab的ws地址 resp requests.get(http://127.0.0.1:9222/json/list) tabs resp.json() page_tab next(t for t in tabs if t[type] page) ws_url page_tab[webSocketDebuggerUrl] ws websocket.create_connection(ws_url) # CDP命令跳转页面 cmd_nav { id: 1, method: Page.navigate, params: {url: https://httpbin.org} } ws.send(json.dumps(cmd_nav)) # CDP命令执行JS获取title cmd_eval { id: 2, method: Runtime.evaluate, params: {expression:document.title, returnByValue:True} } ws.send(json.dumps(cmd_eval)) ret json.loads(ws.recv()) print(ret) ws.close()CDP 爬虫高频 CDP 命令参考CDP Method作用Page.navigate打开网页Runtime.evaluate执行 JS 代码拿返回值Page.captureScreenshot页面截图Network.enable开启网络抓包Network.setRequestInterception拦截 / 修改请求、mock 响应Network.getResponseBody获取接口返回 bodyPage.waitForLoadEvent等待页面加载完成Storage.getCookies获取浏览器全部 cookieCDP 爬虫优缺点直接操控真实 Chrome渲染 SPA、JS 加密页面可以拦截、修改、mock 网络请求拿到接口原始 json复用真实浏览器登录态user‑data‑dir绕过登录没有 chromedriver 版本匹配问题。缺点CDP 本身会留下指纹部分高级反爬可以检测 CDP 连接GitHub只能用于 Chromium 内核浏览器Firefox 用 BiDi 协议裸 CDP 要处理大量异步事件代码复杂优先高层封装库。实践建议普通爬虫 → Playwright必要时调用new_cdp_session()执行原生 CDP 指令需要复用你手动登录好的 Chrome手动启动--remote‑debugging‑port9222程序 attach 上去Docker 部署使用chromium镜像启动开启远程调试端口反爬强站点不要裸 CDP搭配指纹伪装库camoufox、undetected‑playwright。2、其他远程操作 DOM思路我们在 Elements 里面找到输入框的 ID使用 JQuery 操作。百度首页已经有 JQuery 了其他网站我们可以在 Console 里执行 JS加载一个。 我们切换到 Console 里直接用 JS 操作DOM执行$(input[namewd]).val(测试); $(form.fm).submit();相当于在百度输入框里输入了测试并点击了“百度一下”按钮。现在再打开 http://127.0.0.1:9222/json 可以看到原来的页面标题已经变成了 “测试_百度搜索”也就说明成功完成了搜索。获取搜索结果依然是在 Elements 里面找到结果列表的 ID然后用 JS 获取内容。 获得结果数量console.log($(#container).find(.nums).text());获得所有结果标题$(#container).find(.c-container).each(function(){console.log($(this).find(h3.t).text())});常用指令Chrome DevTools Protocol 的指令分为三十多个大类每类又有若干个指令这里不能一一介绍只选择几个简单而常用的指令介绍一下跳转到指定页面https://chromedevtools.github.io/devtools-protocol/tot/Page/执行JS函数https://chromedevtools.github.io/devtools-protocol/tot/Runtime/获取资源树https://chromedevtools.github.io/devtools-protocol/tot/Page/获取资源https://chromedevtools.github.io/devtools-protocol/tot/Page/其中 Page.navigate 是必备指令用于跳转页面。而 Runtime.evaluate 的效果等同于在 Develop Tools 的 Console 控制台执行指令基本可以执行任何js指令模拟输入输出渲染后的 html 用它都可以轻松搞定可以说是大杀器了。获取资源树和获取资源指令则用于获取浏览器当前原始请求的数据可以用它来构建Develop Tools的Source树。可以说利用 Develop Tools 实现的功能我们都可以通过 Chrome DevTools Protocol 实现Chrome 自己也内置了一个官方的实现用 Chrome 直接访问页面信息的 devtoolsFrontendUrl 即可看到和按 F12 调用出来的 Develop Tools 基本一模一样。
返回列表