返回知识中心
身份

金融数据采集的浏览器要求

受监管数据采集比普通抓取多出四项要求:会话绑定单一配置文件、二次验证作为状态变更、记录 TLS 期望,以及逐请求审计记录。

BotBrowser Team

文档中心

想直接进入 身份 文档吗?

这篇文章属于知识中心的指南库。若你要步骤化配置、参考说明和持续更新,请直接进入对应 docs 分区。

金融数据采集不是普通页面抓取的困难版本,而是另一类问题,因为数据源背后通常有账户、会话、二次验证和数据协议。BotBrowser 文档说明了按上下文分配的指纹包与由配置文件驱动的浏览器取值,因此一次采集会话可以始终绑定到同一个已声明身份。它不向金融机构做认证、不保存凭据、不完成多因素验证,也不替代持牌数据源。在设计任务之前,先确认一条被授权的路径。

四项构造出来的要求:会话绑定到单一配置文件、二次验证视为会作废在途工作的状态变更、记录 TLS 期望、逐请求审计记录,并注明存在持牌数据源时用其替代浏览器任务。

摘要

  • 受监管的金融数据通常有持牌路径。先确认供应商数据源、官方 API 或约定导出,把浏览器任务当作需要单独理由的兜底方案。
  • 把一次已认证会话绑定到一个配置文件。若一次运行中途换到第二个配置文件继续同一会话,它已经失去了说明自己是谁的能力。
  • 二次验证是一次状态变更。验证之前发出的在途请求作废,不可重试。
  • 记录你所依赖的 TLS 期望,以及实际观察到的通道属性。「连上了」不是审计结论。
  • 保留逐请求审计记录,写清路由、结果与时间,绝不保存凭据值本身。

目录

普通抓取没有的四项要求

普通页面抓取可以用一个 URL、一个解析器和一份调度描述清楚。受监管数据的任务还必须回答:它是谁、它被允许做什么、数据源打断它时发生了什么。这些问题不出现在通用抓取清单里,漏掉它们会产出一份日后没人能辩护的数据集。

要求避免的失败记录字段
会话绑定到配置文件同一会话在第二个浏览器身份下被悄悄续用session_id、profile_id
二次验证作为状态变更数据源要求验证后重放在途请求auth_state、voided_at
记录 TLS 期望未经检查地假定通道已完成认证expected_channel、observed_channel
逐请求审计记录采集中无法归属到某次被授权的运行request_id、outcome、observed_at

每一行背后都是具体失败,而不是抽象原则。第一行防止一次运行在中途分裂身份。第二行防止客户端把验证当成值得重试的瞬时错误。第三行防止用「请求成功了」代替「通道是我假定的那个」。第四行防止数据集的来源只存在于某个人对那次运行的记忆里。

把会话绑定到一个配置文件

MDN 把 Authorization 请求头描述为用户代理向服务器提供凭据、从而完成认证的方式,通常发生在服务器用 401 Unauthorized 和 WWW-Authenticate 响应初始请求之后。那段描述讲的是一次请求与响应的交换。采集会话是更长的对象:它跨多个请求,可能绑定到 cookie 或令牌,并且由服务器决定它是否仍然有效。

对浏览器任务的影响是:会话与浏览器身份必须一起绑定、一起记录。如果一次运行在某个配置文件下开始、遇到问题后换到另一个配置文件继续,得到的数据来自一个已声明身份在中途改变的会话。即使每个请求都成功,这次运行也无法再说明它是谁。

会话连续性分析 把客户端保留与服务器接受分开:留着 cookie 不等于服务器仍然承认它。这里这个区分更重要,因为金融数据源通常把会话绑定到 cookie 之外的东西。请把绑定显式记为一对值,并在任一半发生变化时拒绝继续。

BotBrowser 的按上下文指纹文档描述了把指纹包分配给一个 BrowserContext,每个上下文携带自己的配置文件、用户代理、时区、区域设置与代理。这正是采集任务可以让某个上下文的已声明身份在整个会话期间保持稳定的机制。它属于浏览器侧输入;它不会让会话获得授权,也不会告诉你服务器是否仍认为会话有效。

有两个操作习惯能让绑定在真实运行中存活。第一个是在创建上下文之前就分配会话标识,并拒绝为同一会话创建第二个上下文。顺序很重要,因为先创建的上下文会欣然接受一个已经存在于别处的会话,而重复只有等到数据源作废其中一个时才被发现。先分配把这个迟来又混乱的作废变成即时的本地错误。

轮换代理的配置文件记录 覆盖了路由变更时的同一套分配纪律,passkey 用户旅程 则说明凭据与它开启的会话为何必须保持为两个对象。第二个习惯是在建立绑定的那一刻就记录,而不是事后从日志重建。分配时写下的记录可以包含运行标识、配置文件标识以及上下文的启动参数,这些正是复核者需要、也最难恢复的事实。从日志重建意味着在两个系统之间对齐时间戳,而这种对齐恰恰会在最值得关注的情形下失败。

绑定还有终止的一面。运行结束时,上下文应被关闭,会话应在同一条记录里标记为关闭。一个在账面上仍开着、浏览器却已消失的会话,最终会被后来的运行当作「在继续某事」而续用,得到的数据横跨两个不同身份却毫无说明。把两半一起关闭是很小的纪律,却能消除一整类来源问题。

最后,把绑定与凭据分开。绑定陈述的是哪个配置文件承载了会话;凭据是证明该会话的材料。运行记录可以安全地携带前者,绝不应携带后者,因为前者是标识符,后者是秘密。把这条界线写进 schema,可以避免后续功能(例如调试导出)把凭据误发进数据集。

把二次验证当作状态变更

二次验证是数据源要求比当前会话所携带的更多证据的那个点。它在金融界面里很常见,而采集代码经常处理错误,因为它以一条看起来很普通的 HTTP 响应出现。

RFC 8446 描述了 TLS 通道及其认证属性,其中包括服务器端总是被认证、客户端可选被认证。二次验证属于另一层:它是应用层要求客户端再次证明某事。当两者在同一次失败请求里同时出现时很容易混淆,而这个错误会让代码重试请求,而不是改变会话状态。

下面的状态模型是构造出来的,不是在某个机构观察到的。它存在的目的是让这次转变显式,从而不给客户端悄悄继续的机会。

事件事件后的会话状态在途工作如何处理
请求被接受authenticated继续
返回验证要求step_up_required作废;每个请求单独重新分类
重新认证完成再次 authenticated只接受新工作;作废的工作不重放
请求被策略拒绝refused记为结果,不重试

第三行是采集代码最容易搞错的一行。重新认证之后会话又能用了,这会诱使你把验证期间失败的一切都重放一遍。那些请求是在数据源已经拒绝的状态下发出的,重放它们产生的观察无法归属到当前的授权。请作废它们、记录作废,并在新状态下开始新工作。

第四行覆盖数据源以策略为由拒绝、而不是要求更多证据的情形。那不是技术故障,重试也不会改变它。请连同原因记录这次拒绝,停止运行,回到授权路径的问题上,而不是把它当作瞬时错误。

二次验证还有时间维度,这是状态表本身没有覆盖的。验证之前发出的请求可能已经被数据源接受,其响应可能在验证到达时仍在途。那些响应并不会因为迟到而无效;它们作为关于当前状态的证据是无效的,因为它们所属的状态已不存在。客户端应按请求发出时的状态分类,而不是按它完成时通行的状态。

这条规则对批处理有实际后果。一个派发一百个请求、再按完成顺序处理结果的作业,会把两个状态的观察交织在一起而没有任何标记。一个按有限分组派发、在组间检查状态的作业,则让边界保持可见。分组大小是吞吐决策,但边界检查是正确性决策,不应为了省一次往返而放宽。

重试策略属于同一模型。在 authenticated 状态下出现网络超时,用一个新请求标识重试一次是合理的,因为状态没变。在 step_up_required 期间超时则不行,因为重试会把请求带进数据源已经拒绝的状态。把这一区分写进重试函数,而不是写在周围的说明文字里,才能让模型在下次重构后依然成立。

记录 TLS 期望与观察到的通道

在受监管数据的任务里,TLS 期望通常由对手方提出,而不是由客户端提出。客户端的工作是记录它依赖了什么、实际看到了什么,让后来的复核者能判断两者是否一致。

连接信任分析 覆盖证书验证与浏览器暴露的连接信号。采集任务在其之上需要的其实很少:一条已声明的期望、一个观察值,以及两者不一致时的判定规则。期望可以是协议版本、服务器必须被认证,或对手方的某项具体策略。观察值则是客户端对该请求真正能读到的内容。

有两种失败模式值得点名,因为两者看起来都像成功。第一种是静默降级:连接完成、数据到达,没有人检查协商出的通道是否是协议所假定的那个。第二种是范围错误:操作方在运行开始时验证一次通道,然后假定它在之后每个请求里都成立。请按请求记录,或至少按连接记录并写明边界,并说明你选了哪一种。

// Constructed fixture: four requests in one run, one channel expectation.
const EXPECTED_CHANNEL = { protocol: 'TLSv1.3', serverAuthenticated: true };
const RUN = { runId: 'run-7', sessionId: 's-41', profileId: 'p-17' };
const requests = [
  {
    requestId: 'r-1',
    route: 'positions',
    protocol: 'TLSv1.3',
    serverAuthenticated: true,
    outcome: 'accepted',
    observedAt: '2026-11-10T09:00:00Z',
  },
  {
    requestId: 'r-2',
    route: 'balances',
    protocol: 'TLSv1.3',
    serverAuthenticated: true,
    outcome: 'step_up_required',
    observedAt: '2026-11-10T09:00:04Z',
  },
  {
    requestId: 'r-3',
    route: 'balances',
    protocol: 'TLSv1.3',
    serverAuthenticated: true,
    outcome: 'accepted',
    observedAt: '2026-11-10T09:03:10Z',
  },
  {
    requestId: 'r-4',
    route: 'statements',
    protocol: 'TLSv1.2',
    serverAuthenticated: true,
    outcome: 'refused',
    observedAt: '2026-11-10T09:03:12Z',
  },
];

const rows = requests.map(r => ({
  request_id: r.requestId,
  run_id: RUN.runId,
  session_id: RUN.sessionId,
  profile_id: RUN.profileId,
  route: r.route,
  outcome: r.outcome,
  observed_at: r.observedAt,
  channel_matches:
    r.protocol === EXPECTED_CHANNEL.protocol && r.serverAuthenticated === EXPECTED_CHANNEL.serverAuthenticated,
}));

const lines = rows.map(
  r =>
    `request_id=${r.request_id} run_id=${r.run_id} session_id=${r.session_id} profile_id=${r.profile_id} ` +
    `route=${r.route} outcome=${r.outcome} channel_matches=${r.channel_matches} observed_at=${r.observed_at}`
);
console.log(lines.join('\n'));

下面的构造输出记录了一次被接受的请求、一次验证状态转变、一次被接受的继续,以及一次被拒绝的请求,并显示 r-4 在通道上出现偏差:

request_id=r-1 run_id=run-7 session_id=s-41 profile_id=p-17 route=positions outcome=accepted channel_matches=true observed_at=2026-11-10T09:00:00Z
request_id=r-2 run_id=run-7 session_id=s-41 profile_id=p-17 route=balances outcome=step_up_required channel_matches=true observed_at=2026-11-10T09:00:04Z
request_id=r-3 run_id=run-7 session_id=s-41 profile_id=p-17 route=balances outcome=accepted channel_matches=true observed_at=2026-11-10T09:03:10Z
request_id=r-4 run_id=run-7 session_id=s-41 profile_id=p-17 route=statements outcome=refused channel_matches=false observed_at=2026-11-10T09:03:12Z

这一行正是记录存在的理由。一个在任务未预期通道上被接受的请求不是干净的观察,数据集应当能在无人重读日志的情况下显示这一点。

如何处理偏差行是策略问题,应当在第一次运行之前回答,而不是在事故当中回答。三种做法都站得住:拒绝该行并停止;接受但打上标记,让下游分析可以排除;接受并把偏差记为提示。正确的选择取决于对手方协议怎么写,所以这个决定属于运行的书面依据,而不属于发现偏差的那段代码。

观察机制本身也需要声明的限制。页面级脚本无法读取自己连接的协商协议;该值必须来自浏览器的网络插桩或发出请求的客户端。记录一个由假定填充的通道字段,比留空更糟,因为空字段会引出问题,而假定的字段会把问题关掉。确实取不到时,请记录取不到以及原因。

版本漂移是最后一块。持续数周的运行可能遇到对手方更改其支持的协议,开头写下的期望会逐渐变错。把期望绑定到日期,并在延长运行时重新核对。没有日期的期望读起来像仍然有效,那正是静默降级在更慢形态下的同一种失败。

构建逐请求审计记录

审计记录对每个请求回答四个问题:哪次运行发出的、在什么身份下、数据源返回了什么、什么时候。其余都是辅助细节。下面的记录是应用层工件,刻意不携带任何凭据值。

字段内容为什么在记录里
request_id该请求的不透明标识在不暴露内容的前提下关联日志行
run_id被授权运行的标识把请求归属到某项许可
session_id会话标识,绝不是令牌值显示发出请求的身份
profile_id上下文启动时使用的配置文件显示已声明的浏览器身份
route端点类别,而不是完整查询串描述请求而不保存参数
outcomeaccepted、step_up_required、refused让状态转变显式
observed_atUTC 时间排序请求并界定运行范围
channel协议与服务器认证结果记录 TLS 期望最终解析成什么

有两个字段需要说明。session_id 不是令牌。把持有者令牌存进审计表,会把审计轨迹变成凭据存储,这比记录本想解决的问题更糟。请记录不透明标识,如需比较同一会话的两条记录则记录哈希。同样的道理适用于 route:记录端点类别而不是带查询参数的完整 URL,因为那些参数常常携带账户或标的标识,而审计并不需要它们。

共享工作站的会话生命周期 对跨用户复用应用了相关规则:谁持有过会话的记录,与会话本身同样重要。每次运行一个配置文件的采集任务更简单,但同样需要这份归属。

记录还需要一项与运行分开的保留决定。随工作数据一起删除的审计轨迹无法回答一个季度之后的问题,而永久保留则会累积任务从未需要的个人数据。请依据协议以及记录本应回答的问题确定保留期,写下来,并把删除变成显式的计划动作,而不是清理时的意外。

审计记录的访问是第二项决定。它常常包含账户标识与端点类别,两者合起来描述客户活动的细节甚至超过数据集本身。请把它限制在需要回答来源问题的人手里,并且读取审计轨迹也要记录日志,而不只是写入。一个无法说明谁查看过它的来源系统,带着它本想消除的同一个弱点。 可验证不等于被授权:审计记录表明某次运行发生过且事后未被修改,它并不证明该运行获得了许可。

最后,让记录可验证。带哈希链的记录,或定期把摘要写到写入方之外的地方,可以表明它在事后未被修改。这一点恰好在记录存在的那类情形里最重要:关于某次运行做了什么的争议。普通表比没有好,但一个写入方可以悄悄改写的表,其证据力弱于内容给人的印象。

何时应改用持牌数据源

大多数受监管的金融数据都有不涉及浏览器的路径。市场数据供应商、官方 API、聚合导出或合同数据源,用已定义的 schema、已声明的更新频率和一份说明你可以如何使用它们的许可,提供同样的值。当这类路径存在时,浏览器任务通常是错误的工具:它为已经提供受支持路径的数据源产出更不稳定的数据集,并带来更多法律暴露。

因此诚实的判定规则不是「浏览器能否到达」,而是「是否存在被授权的路径;若不存在,究竟是什么授权了这条」。如果后半句的答案是某人对一封邮件的记忆,那不是授权。请把路径及其依据写进运行记录,让下一个人继承答案而不是假定。

schema.org 的 FinancialProduct 类型很好地说明了这条界线。它为描述金融产品定义了词汇,包含 annualPercentageRate 与 interestRate 等属性,并指出年化百分比利率与计算出的利率并不相同。这套词汇告诉你如何命名字段;它不说明数据源是否发布这些字段、已发布的值是否最新,也不说明你是否可以采集。

常见问题

登录成功是否意味着采集被授权?

不是。认证确立的是会话是谁,而不是操作方可以如何使用数据。授权来自机构条款或另行签订的协议,一次可用的会话不能替代其中任何一个。

二次验证之后同一会话还能继续吗?

重新认证完成后可以,但验证期间所做的工作不属于那次延续。请作废那些请求、记录作废,并在新状态下开始新工作。

审计记录应当保存访问令牌吗?

不应。请保存不透明会话标识,必要时保存哈希。把令牌存进审计表会把审计轨迹变成凭据存储。

BotBrowser 会向金融机构做认证吗?

不会。它提供由文档描述的、基于配置文件的浏览器输入,包括按上下文的指纹包,让会话绑定到同一已声明身份。凭据、验证挑战与数据许可都在其范围之外。

来源

实践结论

从被授权的路径开始。如果存在持牌数据源或官方 API,就用它,把浏览器任务排除在设计之外。当浏览器任务确实是受支持的路径时,把会话绑定到一个配置文件,把二次验证建模为作废在途工作的状态转变,为每个请求把 TLS 期望与观察到的通道记录在一起,并保留一份写明运行、身份、结果与时间且不保存凭据的审计记录。正是这四项要求,让受监管数据集在运行结束之后仍然站得住。

#金融数据采集#会话绑定#浏览器自动化

本文属于指南: 浏览器身份表面:一致性实用总览

在 BotBrowser 里跑一遍同样的检查

加载 profile,让刚读到的这些信号在浏览器内部保持一致,并在正式上线前先在自己的机器上确认结果。