Chrome DevTools Protocol (CDP)是 Chrome 开始开放的一个WebSocket通信协议。 可以访问 https://chromedevtools./devtools-protocol/ 官方文档查看websocket通信时的各种接口调用参数。 接口通信使用json格式: 请求: { "id": "消息ID", "method": "方法名称", "params": {} } id: messageId,数字类型,不能为0,最好不要重复,要通过messageId区分响应信息 method: CDP 方法名称(Browser.getVersion、Page.getResourceTree...) params: 请求方法参数 响应: { “id”: "请求时传入的消息Id" , "result": {} } 开发者工具的所有操作都是遵循的这个协议,也就是说可以通过这个协议,绕开chrome 各种限制(ಥ_ಥ),比如获取网页所有标签详细信息(包括嵌套的iframe)。 执行Chrome DevTools Protocol 方法:DevToolsClient 是CefSharp 专门对 CDP 接口做的的封装(Page、DOM、Browser...等等),或者通过ExecuteDevToolsMethodAsync手动执行方法: 声明DevToolsClient全局变量://声明全局变量 DevToolsClient devTool = null; //添加ChromiumWebBrowser初始化事件,初始化时赋值 private void Form1_Load(object sender, EventArgs e) { DevToolsClient chromiumWebBrowser1.IsBrowserInitializedChanged += new EventHandler(delegate { devTool = chromiumWebBrowser1.GetBrowser().GetDevToolsClient(); }); } 执行自定义方法://添加一个执行方法 public async Task<string> ExecuteDevToolsMethods(string method, IDictionary<string, object> param = null) { DevToolsMethodResponse resp = await devTool.ExecuteDevToolsMethodAsync(method, param); return resp.ResponseAsJsonString; } //执行 private void button1_Click(object sender, EventArgs e) { ExecuteDevToolsMethods("DOM.getDocument").ContinueWith(new Action<Task<string>>((result) => { Console.WriteLine(result.Result); })); } 注意: 不要使用Wait()等待函数,不然会导致卡死 或者使用CefSharp封装好的对象调用:private async void button1_Click(object sender, EventArgs e) { await devTool.Browser.GetVersionAsync().ContinueWith(new Action<Task<GetVersionResponse>>((resp)=> { Console.WriteLine(resp); })); } 如果使用CefSharp封装对象调用时,需要在执行方法体上添加async/await,才不会导致程序卡死。 可以看一下 stackoverflow 中锁死的几种情况:https:///questions/65895251/cefsharp-use-devtoolsclient-execute-method-after-call-wait-function-waiting/65895577?noredirect=1#comment116512155_65895577 不熟悉async/await的原理,如果各位有好的处理建议,请留言,非常感谢! 调试CDP接口:配置CefSettings, 指定CefSharp 启动时打开远程调试端口: CefSettings _settings = new CefSettings(); _settings.RemoteDebuggingPort = 32999; Cef.Initialize(_settings); 一定要在创建窗体时执行配置全局CefSettings配置: public Form1() { InitializeComponent(); CefSettings _settings = new CefSettings(); _settings.RemoteDebuggingPort = 32999;//调试端口,一会程序启动后,需要访问这个端口 Cef.Initialize(_settings); } 如果在其他地方配置时会报(暂时还没找到原因...): CEF can only be initialized once per process. This is a limitation of the underlying CEF/Chromium framework. You can change many (not all) settings at runtime through RequestContext.SetPreference.
这时启动程序,不出意外的话,直接访问: {ip}:{port}(localhost:32999): 和chrome的远程调试页面比,要简陋一点点.... 页面中列出浏览器端(CefSharp)当前打开了几个网页,打开开发者工具,切换到ws标签,在点进网页的同时,会发现建立了一个websocket长连接,每一个网页都有属于自己的一个websocket链接地址。 注意: 一定要点进网页前打开开发者工具开始监听websocket,点进页面后,在打开开发者工具监听就晚了,因为websocket是长连接,在一次通信过程中,只会建立一次链接,如果在建立链接时没有打开开发者工具开启监听,ws标签下就一直不会有websocket实时通信内容..
手动调用CDP接口:访问 {ip}:{port} (localhost:32999) / json 获取websocket链接:
返回结果是一个数组,数组中每个元素对应的就是当前浏览器端打开的网页信息,webSocketDebuggerUrl字段值就是链接网页是websocket调试地址. 例如,调试 百度页 , 通过websocket工具直接链接:
Browser.getVersion: 获取浏览器端信息
或者通过DOM.getDocument获取百度页面标签内容(包含iframe嵌套iframe,没有同源限制,可以获取所有标签内容): DOM.getDocument 获取网页文档层级结构. 参数: depth[可选]: integer (递归检索子节点深度,默认为1) pierce[可选]:boolean(是否遍历iframes下内容(个人理解,可能有误,请参照谷歌官网文档),默认为false) 返回: root: Node对象
在执行DOM、Page.等其他模块时,最好先执行DOM.enable开启模块代理(看开发者工具在打开页时,总是先enable一堆模块...)
希望对你有帮助...୧(﹒︠ᴗ﹒︡)୨ |
|