← 返回项目档案

项目复盘 · 2018

海纳:从多源采集到可复用的数据服务

一项把法律文书、专利、投融资和行业数据持续转化为内部 API 的数据基础设施工程。

数据平台数据采集搜索服务数据治理

数据型公司很容易积累大量爬虫,却不一定拥有真正可复用的数据资产。脚本可以完成一次下载,但产品需要持续更新、结构统一、失败可恢复、来源可追踪,并能通过稳定接口被多个团队使用。

“海纳”项目正是在这种背景下展开。它没有把自己定位为独立产品,而是为研究、搜索和客户项目提供数据 API,持续建设法律文书、专利、投融资和汽车等数据能力。

多条数据线,共用一套交付目标

项目同时推进几类差异很大的数据任务:

  • 法律文书:获取文书标识与详情,将正文和案件字段结构化;
  • 专利:采集列表、摘要、全文、法律状态、引用与同族信息;
  • 投融资:整合境内外公司、机构和融资事件,处理别名与重复记录;
  • 汽车:采集车型和车主口碑,为后续汽车市场分析平台提供数据;
  • 通用服务:维护 Elasticsearch、MongoDB 等数据系统,并建设统一 API。

这些任务的来源、更新频率和数据形态各不相同,但交付标准相似:先保存原始证据,再转换为结构化记录,最后通过搜索或接口供上层产品调用。

代码架构:用分段管线隔离来源与存储

保留下来的代码不是一个单体仓库,而是一组按阶段拆开的执行程序。Python 与 Scrapy 适配网页和接口,Selenium 处理需要浏览器执行的页面;文书标识和任务状态曾进入轻量键值存储或消息队列;Go 程序再以并发工作协程完成标识同步、详情下载和字段过滤。原始或半结构化结果主要进入 MongoDB,稳定关系进入 MySQL,面向全文检索的文档进入 Elasticsearch,上层服务通过 API 消费。

这套结构的亮点是把来源访问、任务进度、原始内容、结构化字段和检索索引分开。解析规则变化时可以从原始内容重建,搜索索引损坏时也不必重新采集。文书同步代码进一步使用带缓冲通道和批量写入控制数据库压力,并允许按日期键范围切分任务。

海纳多源数据的共同处理骨架
来源目录标识发现持久任务队列详情下载
详情下载原始快照来源解析器结构化记录
结构化记录字段校验文档库全文索引
下载失败失败队列限次重试原始快照
字段未知待分析队列规则升级重新解析

文书同步器的历史实现用缓冲通道、多工作协程和单写入协程控制压力。下面是保持其处理意图、但补上显式关闭与尾批刷新后的等价伪代码。

等价伪代码

text
jobs = channel(buffer=job_buffer)
results = channel(buffer=result_buffer)
producer.scan_date_range(start, end, jobs)
producer.close(jobs)
worker_group.start(worker_count)
worker.consume(jobs):
  raw = fetch_document(job.id)
  parsed = execute_and_parse(raw, timeout=parse_timeout)
  results.send(outcome(job.id, parsed))
worker_group.wait()
results.close()
for outcome in results:
  batch.append(outcome)
  if batch.size >= batch_limit or flush_timer.elapsed:
    search_index.bulk_write(batch)
    ledger.record(batch)
    batch.clear()
search_index.bulk_write(batch)

但多个仓库分别维护配置、连接和错误处理,缺少统一作业标识与跨阶段状态机。部分程序只在日志中报告进度,失败批次没有稳定落盘;代码历史也出现过不应入库的连接信息。更成熟的架构应以同一个批次标识贯穿发现、下载、解析、校验、入库和索引,并由集中配置与秘密管理服务提供运行参数。

三个月里,管线怎样一步步成形

事项时间线显示,2018 年 3 月底并行启动法律文书、专利、投融资、数据接口和搜索服务交接;4 月上旬针对文书同时试验 Go 抓取、Python 小批量下载和浏览器集群,并为专利处理验证码、检索格式与访问受限。4 月下旬,任务从“能下载”转向失败归位、按天增量、详情地址发现和邮件进度通知。5 月才集中出现文书标识同步、正文结构化、全文索引、搜索接口和接口说明。

这个顺序说明系统不是按预先完成的总架构一次实现,而是先通过多条方案找到可行入口,再补状态、失败补偿和消费接口。5 月底的总结任务中,投融资总结完成,而专利、文书数据接口和文书采集总结仍开放;各子线不能被写成同等成熟。

法律文书:规模化下载之后还有结构化

法律文书数据需要处理查询结果数量限制、分页、网络波动和页面变化。项目把流程拆成文书标识发现、详情下载、失败任务回收、增量同步和字段结构化等阶段。保留的 Go 与 Python 仓库分别承担下载、同步、过滤和后期清洗。

这种拆分避免了某一步失败后重跑整个任务。先保存文书标识,可以让下载任务重复执行;失败记录回到队列,可以单独补采;原始文书与结构化结果分开保存,也便于解析规则更新后重新处理。

代码与工单同时表明,结构化并未在项目早期完全结束。部分记录仍处于中间存储,详情字段和全文获取也受来源变化影响。因此,“获得大量文书标识”不能等同于“已经形成完整、可查询的结构化文书库”。

现存 Go 解析器嵌入 JavaScript 运行时,伪造页面选择器与回调,让来源脚本把隐藏字段写入 map;随后用 DOM 锚点把正文分成文首、当事人、诉讼记录、基本事实、裁判理由、判决和落款。人员再按已知姓名、冒号、角色前缀和全角空格逐级识别,法规则保留法规名、法条名和正文。它比正则硬切全文更有适应性,但执行来源脚本缺少资源隔离,未知字段又只写日志,是“覆盖面优先、失败治理滞后”的典型实现。

同步程序把日期分片写入缓冲通道,多协程负责脚本提取与结构化,单一消费者按批量或半秒定时写入搜索引擎。退出条件却观察通道瞬时长度,没有关闭通道和等待全部工作协程;生产者结束时,正在处理而尚未输出的数据可能不在长度统计中。尾批丢失不会在下载总量里显现,必须用输入、成功、失败和最终落库数量对账。

专利:来源变化决定维护成本

专利数据包含列表、摘要、申请人、分类、全文、法律状态、引用和同族等多层信息。项目先集中获取列表与部分详情,再逐步补充全文和关系型字段。

实际执行中,来源网站的查询格式、接口版本和访问行为不断变化,使一次可用的采集规则很快失效。历史记录显示,团队需要反复调整日期查询、请求流程和失败恢复策略。这类维护成本提醒我们:外部网站采集不是一次性开发任务,而是一项需要监控、版本管理和合规评估的长期服务。

投融资:合并比采集更难

投融资数据来自多个境内平台和境外数据源。不同来源对公司名称、融资轮次、币种、投资机构和日期的表达并不一致。项目通过公司全称、别名、主页和其他属性合并记录,同时保留来源 ID,形成统一的公司与融资事件结构。

真正困难的是实体解析。公司可能使用品牌名、工商名称或历史名称,同一轮融资也可能在多个来源中出现不同金额和投资方表述。可靠的合并流程需要保留原始值、匹配依据和来源关系,而不是只输出一条无法追溯的“最终答案”。

投融资代码把组织、人物、融资、投资、并购、上市和关系拆成独立集合,并保留来源标识,说明团队已意识到事件与主体不能塞进一张宽表。问题在于增量快照仍依赖人工切换日期配置,失效记录清理没有闭环;缺少“来源记录最后出现时间”和撤销语义时,数据库会持续保留已经更正或消失的旧事实。

数据服务需要可靠性,而不只是容量

项目曾经历主机磁盘故障。没有备份或副本的数据服务需要重建,而采用复制机制的数据受到的影响较小。这次事件暴露了采集型项目常见的风险:团队把注意力放在“抓到了多少”,却容易低估数据恢复、索引重建和服务迁移的成本。

对于此类平台,原始数据、结构化结果和搜索索引应采用不同的恢复策略:

  1. 原始数据应长期保存并校验完整性;
  2. 结构化数据需要备份、版本和变更记录;
  3. 搜索索引应能够从上游数据自动重建;
  4. 采集进度和失败队列应独立持久化;
  5. 关键服务至少需要副本或经过演练的恢复流程。

数据质量不能靠词典规模解决

项目还记录了中文分词和命名实体识别评测。加入自定义词典后,部分公开测试集的分词得分反而下降;企业识别错误则同时受到训练样本标注和分词结果影响。

这说明领域词典并非越大越好。金融、公司和专利名称需要领域适配,但每次规则变化都应在固定评测集上验证,并单独观察不同文档类型。数据服务只有同时记录覆盖率、准确率和失败类型,才能避免为了多识别一些实体而制造更多错误关联。

项目留下的经验

  • 采集流程应拆分为发现、下载、解析、校验、入库和发布,保证每一步可以独立重试。
  • 原始记录、清洗结果和搜索索引不能互相替代,应分别制定备份与重建策略。
  • 跨来源公司与事件合并必须保留来源 ID、原始值和匹配依据。
  • 外部来源变化需要监控和版本管理,不能依赖人工发现数据停止更新。
  • 数据量不是唯一成果指标,结构化覆盖率、更新延迟、失败率和恢复时间同样重要。
  • 并发管线必须用显式关闭、等待和数量对账证明尾批已写入,不能依赖队列瞬时长度判断完成。
  • 执行来源脚本的解析器需要隔离、超时与固定回归样本;未知字段应进入待分析队列。
  • 多来源事件要同时管理新增、更正与失效,不能只做追加式增量。
  • 采集活动应遵守来源条款、访问限制和个人信息处理要求。

证据边界

Jira 中保留 94 条海纳相关事项,其中 75 条完成、7 条处理中、12 条待办。Confluence 保存 9 篇项目与子项目总结,相关代码分散在至少九个 GitLab 仓库中,能够证明文书、专利、投融资和汽车数据工作确实开展。

现有记录包含不同阶段的数据量目标和阶段性统计,但缺少统一验收口径,部分结构化与全量补采事项也未完成。本文确认项目建立了多条采集与处理链路,并能从代码中确认 Python、Go、Scrapy、Selenium、MongoDB、MySQL、SSDB、消息队列与 Elasticsearch 等局部实现;但不把下载量直接表述为最终可用数据量,也不推断所有组件曾以同一架构长期稳定运行。