Runtime.evaluate是什么?如何通过PowerShell直接调用Chrome相关API?
1. Runtime.evaluate 具体定义
Runtime.evaluate是Chrome DevTools Protocol(简称CDP,Chrome开发者工具协议)中Runtime域下的核心控制命令,作用是向指定的浏览器执行上下文(可以是普通页面、Service Worker、扩展后台页等任意JS运行环境)传入JavaScript表达式并执行,同步返回执行结果、运行时报错、Promise决议结果等信息。
你查阅文档看到的ChromeDriver执行JS操作的逻辑是准确的:ChromeDriver做JS注入、页面DOM操作、状态读取这类操作时,底层就是通过CDP通道向Chrome发送Runtime.evaluate命令,携带要执行的JS代码完成对应操作,不存在特殊的"发送Chrome Javascript文件"的独立逻辑,所有JS执行逻辑都走这个命令完成参数传递和结果回传。
2. 所属API类型说明
Runtime.evaluate不属于普通网页环境可调用的前端Web API,它是Chrome对外暴露的调试控制层专属API,仅在Chrome开启远程调试模式时,通过约定的CDP协议通道才可调用,普通网页内运行的JavaScript无权限访问该接口。
除了ChromeDriver,Puppeteer、Playwright、Selenium 4以上版本的浏览器自动化能力,底层对Chrome的JS执行操作也全部基于这个命令实现。
3. PowerShell 直接调用的实现方法
调用前需要先完成前置准备:用指定启动参数拉起Chrome实例,开启远程调试端口,注意不要和本地已运行的普通Chrome实例共用用户数据目录,否则调试端口会无法正常监听:
# 启动带远程调试端口的Chrome实例,路径替换为本地chrome.exe实际路径 Start-Process "C:\Program Files\Google\Chrome\Application\chrome.exe" -ArgumentList "--remote-debugging-port=9222","--user-data-dir=C:\temp\chrome_debug_profile"
等待Chrome启动完成后,就可以通过PowerShell原生的WebSocket客户端连接CDP接口,调用Runtime.evaluate执行自定义JS,完整示例代码如下:
# 1. 获取当前所有可调试的页面目标,定位要控制的页面对应的WebSocket地址 $targets = Invoke-RestMethod -Uri "http://localhost:9222/json" -Method Get $targetPage = $targets | Where-Object { $_.type -eq "page" } | Select-Object -First 1 $wsUrl = $targetPage.webSocketDebuggerUrl # 2. 建立WebSocket连接 $ws = [System.Net.WebSockets.ClientWebSocket]::new() $cts = [System.Threading.CancellationTokenSource]::new() $ws.ConnectAsync([Uri]$wsUrl, $cts.Token).Wait() # 3. 构造Runtime.evaluate的CDP请求报文,id为自定义请求序号,method固定为Runtime.evaluate # 示例为执行JS获取当前页面标题 $requestBody = @{ id = 1 method = "Runtime.evaluate" params = @{ expression = "document.title" # 替换为需要执行的任意JS代码 returnByValue = $true # 设为$true会直接将执行结果序列化为JSON返回 awaitPromise = $true # 设为$true会等待JS中的Promise执行完成后再返回结果 } } | ConvertTo-Json -Depth 5 # 4. 发送请求 $sendBuffer = [System.Text.Encoding]::UTF8.GetBytes($requestBody) $ws.SendAsync([ArraySegment[byte]]::new($sendBuffer), [System.Net.WebSockets.WebSocketMessageType]::Text, $true, $cts.Token).Wait() # 5. 接收并解析返回结果 $recvBuffer = [byte[]]::new(4096) $recvResult = $ws.ReceiveAsync([ArraySegment[byte]]::new($recvBuffer), $cts.Token).Result $responseText = [System.Text.Encoding]::UTF8.GetString($recvBuffer, 0, $recvResult.Count) $responseObj = $responseText | ConvertFrom-Json # 输出执行结果 Write-Host "JS执行返回结果:" $responseObj.result.result.value # 关闭连接 $ws.CloseAsync([System.Net.WebSockets.WebSocketCloseStatus]::NormalClosure, "done", $cts.Token).Wait()
注意:如果需要和页面做复杂交互,可以调整
Runtime.evaluate的params参数,比如开启includeCommandLineAPI参数后,执行的JS里可以直接使用$x、$$这类和DevTools控制台一致的工具函数。
内容的提问来源于stack exchange,提问作者Harry

