Skip to content

可靠的数据采集:上下文校验、UTF-8 留档与证据口径 ​

浏览器自动化把可见页面、接口响应与调用留档连接起来。将动作执行、输出处理和业务结论分开记录,可以减少重复操作,并让分析结果可以追溯。本章只介绍通用采集能力,不包含具体应用的业务报告。

1. 使用明确的客户端入口 ​

powershell
dsb methods
dsb --id 1001 start --browser chrome --headful
dsb --id 1001 run go_to_url -p url=https://example.com --out navigation.json
dsb --id 1001 state --text-only

methods 是 CLI 子命令;协议方法使用 dsb run list_methods。任务 ID 使用数字,先确认教学 ID 没有被占用。已有登录态优先从页面的账号入口和受限内容确认,不需要导出整份 Cookie。

--select data.text 只接受一个字段路径,不是多字段查询语法。需要多个字段时用 --out 保存完整回执,再由读取程序投影。有关请求前校验和字面逗号键的兼容规则,见 客户端。

输出结果和执行结果分开 ​

字段存在与否只能在收到响应后判断。输出阶段退出码 3,并不表示浏览器动作未执行。先读取当前会话留档或 dsb last,必要时读取新的页面状态,不要重新发送点击或提交。对 go_to_url 同样适用:不必为了恢复输出再导航一次。

--out 保存完整响应且优先于 --select,不能用两者的组合断言投影路径存在。明确缺失的字段与值为 JSON null 的字段也要区分。

2. UTF-8 完整留档 ​

powershell
dsb --id 1001 state --out state.json
dsb --id 1001 js "@collect.js" --out records.json

客户端直接写入 UTF-8 JSON,不需要经过 shell 文本重定向。Windows PowerShell 的 > 文件 可能生成 UTF-16;2>&1 会把诊断和正文混合,不能再当作纯 JSON。读取时使用宿主提供的文本读取工具,明确以 UTF-8 解释客户端留档。

如果旧文件被识别为二进制,优先读取客户端原始留档,不要绕过读取工具或重新执行业务动作。不得通过寻找输出中第一个 { 或字符串截断来猜测 JSON 边界;数组响应、摘要和日志都可能破坏这种假设。终端展示可以精简,完整原文必须先保存。

3. 相对请求先检查文档上下文 ​

页面内 fetch("/api/records") 相对当前文档的 document.baseURI 解析,不会自动找到另一个子域名。credentials: "same-origin" 控制凭据发送,不负责切换站点;不同端口也属于不同 origin。选定 iframe 时,应在同一个 frame 内执行校验和读取。

保存以下示例为 collect.js,把占位站点与接口替换为实际观察到的目标;先导航到目标页面,读取新状态,再执行:

javascript
async () => {
  const expectedOrigin = "https://example.com";
  const target = new URL("/api/records", document.baseURI);
  if (location.origin !== expectedOrigin || target.origin !== expectedOrigin) {
    return {
      status: "ORIGIN_MISMATCH",
      currentOrigin: location.origin,
      targetOrigin: target.origin,
      expectedOrigin,
      requestsIssued: 0
    };
  }

  const response = await fetch(target.href, {
    credentials: "same-origin",
    redirect: "error"
  });
  if (!response.ok) {
    throw new Error("HTTP " + response.status);
  }
  const contentType = response.headers.get("content-type") || "";
  if (!contentType.includes("application/json")) {
    throw new Error("Expected JSON response; verify page and login state");
  }
  const payload = await response.json();
  if (!Array.isArray(payload.records)) {
    throw new Error("Expected records array");
  }
  return {
    status: "PASS",
    sourceUrl: target.href,
    fetchedAt: new Date().toISOString(),
    fetched: payload.records.length,
    displayed: payload.records.length,
    truncated: false,
    records: payload.records
  };
}

Failed to fetch 不是 CORS 的专用错误。先核对当前页、请求 URL、重定向和登录状态,再结合网络记录及控制台定位原因。无法确认时保留原始错误并标记原因待定,不把网络异常当作空结果。示例拒绝重定向;确有重定向需求时应单独检查目的地,而不是关闭浏览器安全机制。

4. 采集量不等于阅读量 ​

建议每条数据保留稳定 ID、来源链接、发布时间、采集时间、完整文本和截断标记,并记录排序、分页、回复层级及退出原因。

口径含义
fetched接口取得的记录数
displayed实际提交给分析者的记录数
read分析者实际检查的记录数,采集脚本不能自动推断
unique按稳定 ID 去重后的数量
valid去除无关、营销、重复、纯表情等内容后纳入分析的数量
truncated文本或展示被截断,需补读后才能声称全文已读

只取首批热评不能声称读完全部评论;一级评论与楼中楼回复应分别计数。广告、转述、未经证实的传言和自述体验分开标注。多条推广文案不能自动算作多份独立需求证据,点赞量也不等于付费意愿。匿名化引用应仍能追溯来源,不收集不必要的身份资料。

5. 有头浏览器验证记录 ​

本轮在两个本地 HTTP origin 上使用真实 Chrome 验证,未访问或修改任何社交账号数据。测试页将断言结果写入 DOM,使人和工具能看到同一份结果。

用例操作与结果状态
站点不匹配当前端口 19481,预期 19482,返回 ORIGIN_MISMATCH,测试脚本请求数为 0PASS
站点匹配导航到 19482 后执行同一脚本,返回两条完整中文记录,fetched=displayed=2PASS
中文留档通过 --out 保存,并用宿主文本读取工具读取两条中文记录PASS
多路径前置校验独立构建的客户端拒绝导航命令中的 data.title,data.url,退出 3;随后读取 URL,浏览器仍在 19482PASS
输出失败恢复读取 URL 后选择不存在的字段,提示动作可能完成;使用同一留档的 last 取得完整响应PASS
截图留证截图回执确认 viewport、未降级;本地 OCR 识别 PASS 与中文内容PASS(视口证据)

同源请求与中文留档的视口证据

图像保存在 assets 目录。这是视口截图,不是整页证明;本轮模型无法直接读取图像,因此只以截图回执、DOM 和 OCR 检查证据,不声称完成视觉布局审核。本地夹具仅验证请求上下文和留档流程,不证明任何第三方网站接口稳定性或市场需求。