【Selenium】Python & Selenium 执行 CDP

前言

这篇文章来吧啦一下由Selenium中用到的cdp(Chrome DevTools Protocol 的调用
用作于记录学习所得,无实质性意义。

以下几篇文章有一点点关系,感兴趣的可以逐一审阅🔎🔎

标题链接
【Selenium】控制当前已经打开的 chrome浏览器窗口https://blog.csdn.net/weixin_45081575/article/details/112621581
【Selenium】控制当前已经打开的 chrome浏览器窗口(高级篇)https://blog.csdn.net/weixin_45081575/article/details/126389273
【Selenium】Selenium获取Network数据(高级版)https://blog.csdn.net/weixin_45081575/article/details/126551260
【Selenium】Python & Selenium 执行 CDPhttps://blog.csdn.net/weixin_45081575/article/details/126556995

本篇文章不讲CDP的原理,只讲它在Python 和 Selenium 中的实现。

知识点📖

Chrome DevTools Protocol 允许使用工具来检测、检查、调试和分析 Chromium、Chrome 和其他基于 Blink 的浏览器。

Chrome DevTools Protocol,简称CDP

看以下 Chrome DevTools Protocol官方文档 ,感兴趣的可以深入去学习了解。

在这里插入图片描述


Selenium的基础

在Selenium中,执行下面的代码,便可以调用 cdp 命令~

# selenium调用 cdp
webdriver.execute_cdp_cmd(command, cmd_args)  

翻看一下它的源码,

  • 该函数是执行 cdp 命令和 获取返回结果
  • 参考链接:https://chromedevtools.github.io/devtools-protocol/,使用示例 务必要参考这里使用,因为不用方法的传参不一样
  • 使用示例:driver.execute_cdp_cmd('Network.getResponseBody', {'requestId': requestId}),下面再解释它的意思

\site-packages\selenium\webdriver\chromium\webdriver.py


CDP操作

下面介绍几种执行 CDP的方法

Selenium 执行 CDP

这里指定端口号为 9527

# -*- coding: utf-8 -*-
# @Time   : 2022-08-28 23:17
# @Name   : selenium_cdp_test.py


from selenium import webdriver
from selenium.webdriver.chrome.options import Options

options = Options()
options.add_experimental_option("debuggerAddress", "127.0.0.1:9527")  # 指定端口为9527
driver = webdriver.Chrome(options=options)  # 启动浏览器
# 显示一个弹框,并输出 hello world
result = driver.execute_cdp_cmd('Runtime.evaluate', {'expression': "alert('hello world')"})
print(result)

代码运行效果如下,

  • 显示一个弹框,并输出 hello world


可能会有疑问,这行代码是什么意思?

driver.execute_cdp_cmd('Runtime.evaluate', {'expression': "alert('hello world')"})

这个时候就需要用到上面的参考网站了,https://chromedevtools.github.io/devtools-protocol/

  • 左侧是对应的 域名 的一个大类
  • Runtime.evaluate 是 计算全局对象上的 expression
  • expression 是我们传进入的 js 语句(这里只有expression 是必选参数,其它的都是可选的~


当然,也还有上面的 Network.getResponseBody

  • Network.getResponseBody 是 为给定 requestId 请求返回内容
  • requestId 是网络请求的唯一标识符

更多的用法,可以通过官方文档学习~


Python使用 requests操作 CDP

这个方法是用过Selenium的源码中找到的,以调试模式执行Selenium,打上断点,一步步跟下去,找到了它发网络请求的地方~

\site-packages\selenium\webdriver\remote\remote_connection.py

再看调试的控制台的信息

结合两图,总结一下

  • method:POST
  • url:http://localhost:55438(这里的端口号是随机的
  • path:/session/$sessionId/goog/cdp/execute
  • sessionId,service_url,(每启动Selenium都会有该参数,且唯一

所以可以得出以下规律,

  • 请求连接:{service_url}/session/{session_id}/goog/cdp/execute(其中{xxx}为要填充的内容(这里的端口号是随机生成的,上一篇文章中有说~
  • data:就是我们传进去的表达式,是一个字典,cmd 为指定方法,params 为所需要携带的参数

你执行以下代码时候,需要替换成自己的 service_urlsession_id

# -*- coding: utf-8 -*-
# @Time   : 2022-08-27 12:41
# @Name   : selenium_cdp_2.py

import time
import json
import requests

# 'http://127.0.0.1:{port}/session/{session_id}/goog/cdp/execute'
url = 'http://127.0.0.1:55623/session/0ce4027784730e1ffb42b334809ed427/goog/cdp/execute'
# 导航当前页面到给定的URL
data_1 = {"cmd": "Page.navigate", "params": {"url": "https://www.baidu.com"}}

data_2 = {
    "cmd": "Runtime.evaluate",
    "params": {"expression": "alert('hello world')"}  # 出来一个弹框
}
resp = requests.post(url, data=json.dumps(data_1))
print(resp)
print(resp.json())

time.sleep(2)
resp = requests.post(url, data=json.dumps(data_2))
print(resp)
print(resp.json())


以上代码执行效果如下所示,

  • 先访问了 baidu
  • 然后 弹出一个 弹窗

但是这个方法有点麻烦,因为需要以调试模式执行,才能知道当前的 session_idservice_url 。下面有个更好的方法~

Python连接 WebSocket 执行 CDP

这个方法就简单的多了,还记得前面的文章吗?

讲到了这个链接:http://127.0.0.1:9527/json

看图右边的 webSocketDebuggerUrl 参数,这是个 WebSocket 的链接,所以使用 WebSocket 进行连接后,我们也可以执行 CDP。


这里值得注意是安装 websocket 模块,要按照这以下顺序

  1. pip install webscoket
  2. pip install websocket-client
# 这里插入代码片
# -*- coding: utf-8 -*-
# @Time   : 2022-08-27 12:00
# @Name   : py_cdp.py

import json
import requests
import websocket


def websocket_conn():
    # websocket_conn 连接
    resp = requests.get('http://127.0.0.1:9527/json')  # 有不懂的看上一篇文章
    assert resp.status_code == 200
    ws_url = resp.json()[0].get('webSocketDebuggerUrl')
    return websocket.create_connection(ws_url)


def execute_cdp(conn: websocket, command: dict):
    # 执行  dp
    conn.send(json.dumps(command))
    # 接受websocket的响应,并将字符串转换为 dict()
    return json.loads(conn.recv())


def main():
    conn = websocket_conn()
    # js = "alert('hello world')" # 弹窗 hello world
    # js = "console.log('hello world')" # 控制台打印 hello world
    js = "location.href='https://www.bilibili.com'"  # 页面跳转
    command = {
        'method': 'Runtime.evaluate',  # 处理 传进去的 expression
        'id': int(),	# id需要传一个整型,否则会报错
        'params': {'expression': js}
    }
    resp = execute_cdp(conn, command)
    print(resp)


if __name__ == '__main__':
    main()

运行效果看下面动图,js代码中指定页面跳转到 B站。


后话

本次的执行cdp操作就介绍到这里了,
怎么样,是不是感觉没用的知识又增加了~🎃🎃
see you.

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是小菜欸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值