Browser Harness 实战:复用已登录 Chrome 完成后台数据查询
连接独立测试 Chrome,在保留人工登录态的情况下读取当前筛选订单表,生成状态汇总,并处理登录失效、错误标签页和字段变化。
后台页面往往已经有人工完成的登录和筛选条件。为了读取一张表,重新启动一个没有 Cookie 的浏览器再做登录,会增加不必要的步骤。Browser Harness 可以连接现有 Chrome,让查询沿用该浏览器的状态。
本文面向维护自有后台的开发者。我们在独立测试浏览器中登录后台,读取当前筛选条件下的一页订单,保存记录和状态汇总。任务只读当前页,不代表导出了整个账户历史,也不会自动提交表单或修改订单。
准备一个明确的浏览器环境
使用 Python 3.12、uv 与受支持的 Chrome。uv 安装方式见 官方安装文档。安装工具:
uv tool install --python 3.12 'browser-harness==0.1.13'
browser-harness recordings disable本地 Chrome 接入不需要 Browser Use 云端 key。保持录制关闭,当前任务只需要页面查询,不需要动作录像。
用单独的测试 Profile 打开 Chrome,在 chrome://inspect/#remote-debugging 中按浏览器提供的选项允许当前实例远程调试。然后在这个 Profile 中人工登录你自己的测试后台。不要假设另一个普通浏览器窗口的登录态会自动出现在当前连接里。
工具连接和 Chrome 权限相关步骤见 Browser Harness 安装说明。
先确认连接的是正确标签页
执行:
browser-harness <<'PY'
print(page_info())
print(list_tabs())
PY比较页面标题和 URL,确认当前标签属于测试后台。若不是,使用 list_tabs 返回的实际目标标识调用 switch_tab(target);不要复制另一台机器的 tab ID。
只在普通网页标签上操作。Chrome 设置页、空白页或已经关闭的标签不是后台查询来源。连接可用只说明能控制这个标签,还要确认登录和筛选状态。
约定后台表格的字段
不同后台的 DOM 不一致,下面明确本文示例所依赖的结构。请把选择器映射到你自己的页面,不要原样假设目标系统存在这些属性:
<div data-testid="filter-summary">2026-10-01 至 2026-10-28,全部状态,当前页</div>
<table data-testid="orders">
<tbody>
<tr data-order-id="o-1001" data-total-minor="1290">
<td data-field="status">paid</td>
</tr>
<tr data-order-id="o-1002" data-total-minor="2500">
<td data-field="status">pending</td>
</tr>
</tbody>
</table>订单 ID 是稳定标识;total-minor 是以分为单位的整数,不能拿展示的“¥12.90”直接转整数;filter-summary 说明当前页面范围。这里的 HTML 是数据合同示例,不是已部署或自动登录的演示后台。
在页面里人工设置所需日期和状态,等表格完成更新后再读取。对于正在维护的自有后台,增加稳定的测试属性通常比依赖第几个 td 更容易维护;无法改页面时,使用当前实际标签和列头完成映射。
一次完整的只读提取与汇总
保持已选择的后台标签,执行下面的 CLI 脚本。它不自动跳转到未知站点,也不清空当前 Cookie:
browser-harness <<'PY'
import json
from collections import Counter
from pathlib import Path
if not wait_for_element('table[data-testid="orders"]', timeout=15):
raise RuntimeError("订单表未就绪;请检查当前标签、登录和加载状态")
result = js("""
(() => ({
source_url: location.href,
scope: document.querySelector('[data-testid="filter-summary"]')?.textContent?.trim(),
rows: [...document.querySelectorAll('table[data-testid="orders"] tbody tr')].map(row => ({
order_id: row.getAttribute('data-order-id'),
total_minor: row.getAttribute('data-total-minor'),
status: row.querySelector('[data-field="status"]')?.textContent?.trim()
}))
}))()
""")
if not result.get("scope"):
raise RuntimeError("缺少筛选范围说明")
seen = set()
totals = Counter()
for row in result["rows"]:
if not row["order_id"] or row["order_id"] in seen:
raise RuntimeError("订单 ID 缺失或重复")
if row["status"] not in {"paid", "pending", "cancelled"}:
raise RuntimeError("订单状态不在本次约定内")
if not isinstance(row["total_minor"], str) or not row["total_minor"].isdigit():
raise RuntimeError("金额必须是非负整数分")
row["total_minor"] = int(row["total_minor"])
seen.add(row["order_id"])
totals[row["status"]] += row["total_minor"]
result["counts"] = dict(Counter(row["status"] for row in result["rows"]))
result["totals_minor_by_status"] = dict(totals)
Path("orders.json").write_text(
json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8"
)
print({"scope": result["scope"], "rows": len(result["rows"]),
"counts": result["counts"]})
PY脚本读取浏览器中的 DOM,并在 CLI 工作目录写 orders.json。空表不会被当作全量订单已清空的证明;需要同时查看页面明确的空结果状态和筛选条件。跨页汇总应另加分页与覆盖检查,不能把本例的当前页金额当作整个日期范围总额。
怎样检查结果
对于上面两行 HTML,预期 paid 一条、pending 一条,相应金额分别为 1290 与 2500 分。真实页面输出应以当前 DOM 为准。
打开 orders.json,核对 source_url 是否属于后台订单页,scope 是否与你刚才设置的日期和状态相符。抽查两个订单 ID 和金额,再检查状态计数。若站点使用多币种,应把币种纳入记录并按币种分组,不能直接把它们相加。
读取完成不应关闭整个用户 Chrome。如果你为任务新建了标签,可以用工具关闭该标签;复用的后台标签由使用者保留。MCP 客户端断开、daemon 结束与 Chrome 退出是不同生命周期,不能用退出一个进程来推断所有浏览器资源都已经关闭。
登录失效和页面变化时怎样恢复
出现登录页。 停止读取,人工在同一测试 Profile 中重新登录,再确认当前 URL 和表格。不要把登录提示保存为“零订单”,也不要在脚本中回填真实密码来掩盖会话失效。
连接到错误标签。 重新列出标签,按实际 target 切换,然后检查 URL。多个窗口同名时不能只根据标题选择。
选择器一直等不到。 判断表格是否正在加载、是否在 iframe 中、是否已改版。若在 iframe,需采用工具支持的对应目标,而不是扩大根页面查询范围猜字段。
状态字段变了。 当前脚本明确拒绝未知状态。核对后台是否新增状态或只是展示文案变更,再修改映射;不要默认归到 paid。
工具异常的形状不同。 CLI 与 MCP 包装层可能把错误作为异常或工具错误返回,不能只检查结果中有没有 error 字段。没有拿到完整结果时,不继续写成功文件。
页面还是旧筛选数据。 确认筛选动作已经完成,等待表格的更新标记而不是固定睡眠。保存 scope,并抽查来源记录,避免在加载过渡时读取旧表。
复用已登录浏览器的价值在于保留当前会话,查询的可靠性仍依赖正确标签、明确范围和字段合同。把这三项保留下来,数据才便于回查。
需要企业代理方案?
我们可根据目标站点、并发规模与稳定性目标提供定制方案。