128 lines
5.5 KiB
PowerShell
128 lines
5.5 KiB
PowerShell
# 用无头 Chrome 截图,做视觉验收
|
|
# 用法: powershell -NoProfile -ExecutionPolicy Bypass -File scripts\shots.ps1 -Base http://127.0.0.1:18080
|
|
param(
|
|
[string]$Base = 'http://127.0.0.1:18080',
|
|
[string]$User = 'admin',
|
|
[string]$Pass = 'daili123',
|
|
[string]$OutDir = ''
|
|
)
|
|
|
|
$ErrorActionPreference = 'Stop'
|
|
$root = Split-Path -Parent (Split-Path -Parent $MyInvocation.MyCommand.Path)
|
|
if (-not $OutDir) { $OutDir = Join-Path $root 'shots' }
|
|
New-Item -ItemType Directory -Force -Path $OutDir | Out-Null
|
|
|
|
$chrome = 'C:\Program Files\Google\Chrome\Application\chrome.exe'
|
|
if (-not (Test-Path $chrome)) { throw '找不到 Chrome' }
|
|
|
|
# 1) 登录拿会话 cookie
|
|
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
|
|
Invoke-WebRequest -Uri "$Base/login" -WebSession $session -UseBasicParsing | Out-Null
|
|
Invoke-WebRequest -Uri "$Base/login" -Method POST -WebSession $session -UseBasicParsing -Body @{
|
|
username = $User; password = $Pass; next = '/calendar'
|
|
} | Out-Null
|
|
$cookie = ($session.Cookies.GetCookies($Base) | Where-Object { $_.Name -eq 'daili_sid' } | Select-Object -First 1)
|
|
if (-not $cookie) { throw '登录失败,拿不到会话' }
|
|
$token = $cookie.Value
|
|
|
|
# 2) 拿一个订阅 ID 用于「追加面板」截图
|
|
$custID = ''
|
|
$subID = ''
|
|
$r = Invoke-WebRequest -Uri "$Base/customers?q=7001" -WebSession $session -UseBasicParsing
|
|
if ($r.Content -match '/customers/(\d+)') {
|
|
$custID = $matches[1]
|
|
$r2 = Invoke-WebRequest -Uri "$Base/customers/$custID" -WebSession $session -UseBasicParsing
|
|
if ($r2.Content -match 'id="sub-(\d+)"') { $subID = $matches[1] }
|
|
}
|
|
|
|
# 3) 启动 Chrome
|
|
$profile = Join-Path $root ('.chrome-profile-' + (Get-Date).ToString('HHmmss'))
|
|
$chromeArgs = @(
|
|
'--headless=new', '--disable-gpu', '--hide-scrollbars', '--no-sandbox',
|
|
'--no-first-run', '--no-default-browser-check', '--disable-extensions',
|
|
'--disable-crash-reporter', '--disable-breakpad',
|
|
'--force-device-scale-factor=1', '--remote-debugging-port=9222',
|
|
"--user-data-dir=$profile", '--window-size=1440,1000', 'about:blank'
|
|
)
|
|
$chromeProc = Start-Process -FilePath $chrome -ArgumentList $chromeArgs -PassThru
|
|
$targets = $null
|
|
for ($i = 0; $i -lt 20; $i++) {
|
|
Start-Sleep -Milliseconds 500
|
|
try {
|
|
$targets = Invoke-RestMethod 'http://127.0.0.1:9222/json'
|
|
if ($targets) { break }
|
|
} catch { }
|
|
}
|
|
if (-not $targets) {
|
|
Stop-Process -Id $chromeProc.Id -Force -ErrorAction SilentlyContinue
|
|
throw 'Chrome 调试端口未就绪'
|
|
}
|
|
$page = $targets | Where-Object { $_.type -eq 'page' } | Select-Object -First 1
|
|
if (-not $page) { throw '拿不到调试目标' }
|
|
|
|
$script:ws = New-Object System.Net.WebSockets.ClientWebSocket
|
|
$script:ws.ConnectAsync([Uri]$page.webSocketDebuggerUrl, [Threading.CancellationToken]::None).Wait()
|
|
$script:msgId = 0
|
|
|
|
function Send-CDP {
|
|
param([string]$Method, $Params)
|
|
$script:msgId++
|
|
$payload = @{ id = $script:msgId; method = $Method; params = $Params } | ConvertTo-Json -Depth 12 -Compress
|
|
$bytes = [Text.Encoding]::UTF8.GetBytes($payload)
|
|
$seg = New-Object 'System.ArraySegment[byte]' -ArgumentList @(, $bytes)
|
|
$script:ws.SendAsync($seg, [Net.WebSockets.WebSocketMessageType]::Text, $true, [Threading.CancellationToken]::None).Wait()
|
|
while ($true) {
|
|
$ms = New-Object System.IO.MemoryStream
|
|
do {
|
|
$buf = New-Object byte[] 131072
|
|
$segR = New-Object 'System.ArraySegment[byte]' -ArgumentList @(, $buf)
|
|
$res = $script:ws.ReceiveAsync($segR, [Threading.CancellationToken]::None).Result
|
|
$ms.Write($buf, 0, $res.Count)
|
|
} while (-not $res.EndOfMessage)
|
|
$text = [Text.Encoding]::UTF8.GetString($ms.ToArray())
|
|
$msg = $text | ConvertFrom-Json
|
|
if ($msg.id -eq $script:msgId) { return $msg }
|
|
}
|
|
}
|
|
|
|
function Shoot {
|
|
param([string]$Name, [string]$Path, [int]$Width = 1440, [int]$Height = 1000, [bool]$SetCookie = $true)
|
|
Send-CDP 'Emulation.setDeviceMetricsOverride' @{
|
|
width = $Width; height = $Height; deviceScaleFactor = 1; mobile = ($Width -lt 600)
|
|
} | Out-Null
|
|
if ($SetCookie) {
|
|
Send-CDP 'Network.setCookie' @{
|
|
name = 'daili_sid'; value = $token; domain = '127.0.0.1'; path = '/'; httpOnly = $true
|
|
} | Out-Null
|
|
}
|
|
Send-CDP 'Page.navigate' @{ url = "$Base$Path" } | Out-Null
|
|
Start-Sleep -Milliseconds 900
|
|
$shot = Send-CDP 'Page.captureScreenshot' @{ format = 'png'; captureBeyondViewport = $false }
|
|
$file = Join-Path $OutDir "$Name.png"
|
|
[System.IO.File]::WriteAllBytes($file, [Convert]::FromBase64String($shot.result.data))
|
|
Write-Host (" shot {0,-16} <- {1}{2}" -f $Name, $Base, $Path) -ForegroundColor DarkGray
|
|
}
|
|
|
|
Send-CDP 'Network.enable' @{} | Out-Null
|
|
Send-CDP 'Page.enable' @{} | Out-Null
|
|
|
|
Shoot 'login' '/login' 1440 900 $false
|
|
Shoot 'calendar' '/calendar' 1440 1000
|
|
Shoot 'customers' '/customers' 1440 900
|
|
if ($custID) { Shoot 'customer-detail' "/customers/$custID" 1440 1100 }
|
|
if ($custID -and $subID) {
|
|
$today = (Get-Date).ToString('yyyy-MM-dd')
|
|
Shoot 'extend-panel' ("/customers/{0}?extend={1}#extend" -f $custID, $subID) 1440 1200
|
|
}
|
|
Shoot 'subscriptions' '/subscriptions?state=all' 1440 900
|
|
Shoot 'packages' '/packages' 1440 800
|
|
Shoot 'package-form' '/packages/new' 1200 940
|
|
Shoot 'customer-form' '/customers/new' 1000 900
|
|
Shoot 'settings' '/settings' 1440 1000
|
|
Shoot 'screen' '/screen' 1600 900
|
|
Shoot 'calendar-mobile' '/calendar' 390 844
|
|
|
|
$script:ws.Dispose()
|
|
Stop-Process -Id $chromeProc.Id -Force -ErrorAction SilentlyContinue
|
|
Write-Host '截图完成' -ForegroundColor Green
|