用Claude Code构建EDGAR数据库
爬取 SEC EDGAR,解析杂乱的 10-K 文件,提取特定章节,构建结构化数据库,并进行简单的分析,全部通过 Claude Code 完成。
微信 ezpoda免费咨询:AI编程 | AI模型微调| AI私有化部署
AI模型价格对比 | AI工具导航 | ONNX模型库 | Tripo 3D | Meshy AI | ElevenLabs | KlingAI | ArtSpace | Phot.AI | InVideo
在上篇文章中,我们从政府 API 获取了结构化数据——按年龄划分的住房拥有率,已经是整齐的表格形式。但很多研究数据并非如此。它们隐藏在 PDF、HTML 文件、监管文件、财报电话会议记录中。从"信息存在于互联网某处"到"我拥有一个可查询的数据集",往往是项目中最困难的部分。
所以我们要做的正是这件事:爬取 SEC EDGAR,解析杂乱的 10-K 文件,提取特定章节,构建结构化数据库,并进行简单的分析——全部通过 Claude Code 完成。整个流程大约需要 30 分钟,并且产生了一个实际的发现。
1、研究问题
事情的起因是这样的:2025 年关税升级一直是市场中主导的政策话题。如果你关注贸易敏感型公司,你一定看到了股价反应、财报电话会议评论、分析师报告。但公司的正式风险披露是如何变化的呢?10-K 中的第 1A 项——风险因素部分——是公司法律要求描述重大风险的地方,也是律师们绞尽脑汁的部分。当新风险出现时,它会在这里体现。
所以问题很简单:在 2025 年关税升级之后,公司在 10-K 风险因素文件中是否增加了与关税相关的语言? 这与更广泛的政策不确定性衡量文献(如 Baker, Bloom & Davis)和风险因素披露研究(如 Campbell et al., 2014)相关。但今天我们只做描述性工作——构建数据集并看看数据中有什么。
2、爬取 EDGAR
我在一个空目录中启动 Claude Code。与上篇文章中我对数据来源含糊其辞不同,这次我确切知道数据在哪里——SEC EDGAR——并且可以给 Claude 一些关于其工作方式的有用上下文。
> ❯ I want to build a dataset of 10-K Risk Factors from SEC EDGAR
to study how tariff-related risk disclosure changed 2022–2025.
Here's what I know about EDGAR:
- Every company has a CIK (Central Index Key)
- The EDGAR filing API is at https://efts.sec.gov/LATEST/
- Rate limit: 10 requests/second, must include User-Agent header
I want 10-Ks for ~30 trade-exposed firms — manufacturing, retail,
tech hardware. Caterpillar, Nike, Apple, Deere, Ford, 3M, Intel
如果你还记得第一个视频,我谈到 Claude 的表现取决于你给出的指示有多清晰和精确。我越精确,它就越不需要随机搜索。Claude 需要在编写代码之前就知道速率限制和 User-Agent 头信息,而不是在遇到 403 错误之后(当然,它在此操作中仍然犯了错——我的坚持不够)。
3、计划模式和交互式设计
有一个值得注意的事情立刻发生了,在前面的视频中没有出现过:Claude 进入了计划模式。它看了看提示词,认识到这是一个重要的多步骤项目,并表示想先设计方法再编写任何代码。它研究了 EDGAR API——获取文档、查看 GitHub 上的示例、理解文件索引结构——然后才提出方案。
然后 Claude 做了一件我想强调的事情:它问了我问题。三个问题:
- 数据库格式:"你想要 SQLite 数据库吗?平面文件?还是两者都要?" 我告诉它我想要 DuckDB——它类似于 SQLite,但我更喜欢这样操作。
- 关键词方法:"你想要关键词搜索、全文提取加标记,还是 LLM 分类(成本更高)?" 我选择了关键词搜索——只查找与关税相关的词汇。
- User-Agent:"User-Agent 头信息应该使用什么实体?你想稍后填写还是现在提供?" 我当场给了它我的名字和邮箱。
Markus 在对话中还提了一个很好的建议:在关税关键词中加入"解放日"(liberation day),因为 2025 年 4 月 2 日是重大关税公告。Claude 立刻更新了关键词列表,加入了"liberation day"和"liberation day tariff"。
在规划阶段之后,Claude 将计划保存到了一个文件中——就像我在第 1 篇文章中描述的有意压缩方法一样。计划包括目标公司列表、数据库 schema、关键词字典和管道架构。然后它清除了上下文窗口,但将计划保留在磁盘上,这样它就可以以完整的上下文预算重新开始,同时保留我们做出的所有设计决策。这正是我们讨论过的模式:研究 → 将计划写入文件 → 新会话读取计划 → 执行。
4、构建和运行管道
Claude 编写了大约 480 行 Python 代码来实现管道。它包含了所有阶段:CIK 查找、文件索引查询、文档下载、使用 BeautifulSoup 进行 HTML 解析,以及结构化存储。实用功能很重要——它缓存下载的 HTML 文件,这样后续运行就不需要重新下载;它记录错误而不会中断批处理;它在元数据中跟踪每次下载尝试。
一个有用的功能:你可以在 Claude 运行长时间进程时排队后续问题。当下载器在处理文件时,我输入了下一个问题,它会等到当前任务完成后才回答。
> Run it for the full list. Let's see how it goes.
脚本找到了 30 家公司中 29 家的 CIK。唯一失败的是 Gap Inc,它在我们的列表中以股票代码"GPS"列出。Claude 找不到它的 CIK,所以我问发生了什么。原来 Gap Inc. 已经改名了,在某些数据集中以"GAP"交易,而不是"GPS"。Claude 查找了正确的 CIK(39911),更新脚本使用正确的股票代码,并重新运行。由于脚本内置了缓存功能,它只需要下载四个新文件——其余的已经在磁盘上了。大约用了 43 秒。
在下载过程中,我还演示了一个有用的功能:我不小心按了 Escape 键,中断了 Claude 的进程。但由于上下文窗口的工作方式,我只需输入"please continue",它就从上次中断的地方继续了。(你也可以按 Ctrl+O 来切换"思考"视图,随时查看 Claude 的内部推理过程。)
5、提取和结构化
文件夹中的原始 HTML 文件不是研究数据。你无法查询它们,无法将它们与 Compustat 关联,除非每次都将所有内容加载到内存中并解析,否则你什么也做不了。我需要一个结构化数据库。
Claude 编写了一个解析器来处理格式差异——而且差异很多。有些文件使用 HTML 的 <div> 标签和 CSS 样式。有些是带有用于格式的点号和破折号的纯文本。章节标题有时是全大写的"ITEM 1A",有时是带句号的"Item 1A.",有时在 <a> 标签内。Claude 的解析器尝试多种正则表达式模式,并优雅地降级处理。
第一次运行从 120 份文件中成功提取了 112 份的 Item 1A。我问为什么有 8 份缺失。Claude 调查后发现 Honeywell 和 Intel 存在格式边缘情况:"Item 1A"和"Risk Factors"出现在不同的行,中间有换行符,但正则表达式要求它们在同一行。Claude 修复了正则表达式以允许换行并重新运行:120 份中成功提取了 119 份。剩下的一份是 3M,它有不寻常的文件结构,需要人工处理。
这就是"95% 很快,最后 5% 需要判断"的模式。对于快速分析,120 份中成功 119 份已经很好了。对于发表的论文,我会回头手动检查 3M 的文件。无论如何,数据库已经建好了。
6、查询数据库
现在是收获的时刻。我有了一个结构化的 DuckDB 数据库,可以真正对数据提问了。
> Which firms mentioned tariffs the most?
Claude 编写了一个查询并返回了具体结果。Deere(约翰迪尔)以最多的关税提及量领先,在 2022-2025 年期间从三次增加到四次。制造和科技硬件公司最频繁地提及关税;零售公司提及最少。沃尔玛直到 2025 年才开始提及关税。AGO 从四次降至零。
上下文片段也很有用。在早期的文件中,你看到的是泛泛的语言:"贸易政策的变化可能对我们的业务产生不利影响。"在 2025 年,你看到的是引用第 301 条、具体关税税率和特定产品类别的具体语言。语言的精确程度追踪了政策的精确程度。
7、扩展到 2010 年
然后我让 Claude 下载同一组公司 2010 年的 10-K 文件,并运行相同的关税关键词分析。比较结果很有趣:即使在 2010 年,大约 30 家公司中有 18 家提及了关税。但强度不同——2010 年 18 家公司总共 25 个关税段落,而 2022-2025 年期间大约相同数量的公司每年有 26 到 35 个。词汇也发生了变化:在 2010 年,术语更加狭窄——"tariff"、"trade restrictions"、"anti-dumping"、"countervailing duties"。到 2025 年,语言扩展到了"trade tension"、"trade dispute"、"trade war"、"liberation day"。风险披露的广度,而不仅仅是频率,已经发生了变化。
这是一个发现。不是因果关系——你需要更多的结构才能得出因果结论——而是一个干净的描述性事实,可以推动更深入的分析。如果你对横截面感兴趣——哪些类型的公司增长最大——你可以在不改变管道的情况下将此扩展到所有 500 家标普公司。扩大样本的成本很低。我们只花了大约 30 分钟就完成了这一切。
8、最终管道
project/
├── data/
│ ├── firm_list.csv (input: tickers)
│ ├── filings/
│ │ ├── AAPL/
│ │ │ ├── AAPL_2022_10K.html
│ │ │ ├── AAPL_2023_10K.html
│ │ │ └── ...
│ │ ├── CAT/
│ │ └── ...
│ ├── filings.db (DuckDB database)
│ └── metadata.csv (download tracking)
├── figures/
│ └── tariff_disclosure.pdf
├── download_filings.py
├── extract_and_structure.py
├── analyze.py
├── requirements.txt
├── Justfile
└── README.md
关键在于数据库。filings.db 是可复用的研究资产——不是原始 HTML 文件,也不是文本提取。一旦你拥有了一个结构化数据库,你就可以:
- 添加新关键词而无需重新解析所有文件
- 与其他数据集关联(文件日期前后的股票收益、来自 Compustat 的公司特征)
- 直接运行 SQL 查询,而不是每次都编写 Python 解析代码
- 将数据库交给不需要重新运行爬取管道的合作者
这是任何文本即数据项目的模式:爬取 → 解析 → 结构化 → 分析。原始文件是中间产品。数据库才是交付物。
9、几点心得
- 前置爬取任务的上下文。 在 Claude 编写代码之前,告诉它有关速率限制、身份验证、API 结构和数据格式的信息。特别是对于 EDGAR,提前提及 User-Agent 要求和 10 次/秒的限制可以避免一整轮调试。
- 让 Claude 向你提问。 这与之前的视频不同。我没有预先指定每个细节,而是给了 Claude 高层任务,它向我询问设计决策:数据库格式、关键词方法、User-Agent 身份。这些是研究决策——我应该来做——但我不需要在初始提示词中预见每一个。
- 自己构建数据库 schema。 或者至少批准它。你需要什么表?哪些关键词重要?应该跟踪什么元数据?Claude 提出了一个 schema,但其中的选择——比如跟踪关键词计数和上下文片段以便抽查——反映了我下游需要的领域知识。这是研究者的工作。
- 断点续传不是可选的。 当你在网络上下载 100 多个文件时,事情必然会失败。超时、速率限制错误、缺失文件、服务器故障。Gap Inc. 的股票代码问题就是一个很好的例子:因为脚本缓存了所有内容,修复股票代码并重新运行只需要下载四个新文件,而不是重新下载全部 120 个。
- 质量报告日后能救你。 提取质量报告——哪些文件解析成功、字数分布、标记异常短的提取——是我们发现 Honeywell/Intel 正则表达式问题和 3M 边缘情况的手段。没有它,你可能几个月后才发现你的样本中有垃圾数据。
- DuckDB(或 SQLite)在研究中被低估了。 我认识的大多数经济学家使用 CSV 和数据框。但对于文本即数据项目,可 SQL 查询的数据库是更好的选择。零配置(它是一个文件),可以用 SQL 查询(Claude 擅长编写),并且自然地处理关系结构——文件有多个关键词,公司有多个文件。你不需要 Postgres 或服务器。只需要一个
.db文件。我更喜欢 DuckDB,但 SQLite 也可以。 - 发现才是重要的。 很容易把爬取当作纯粹的基础设施任务——"我建了一个管道,完成了。"但整个目的是学到一些东西。即使是一个简单的描述性分析(关税关键词增加了,词汇从狭义的贸易术语转变为更广泛的政策风险语言,沃尔玛直到 2025 年才提及关税)也让你对管道正常工作和数据真实可靠有了信心。
原文链接: From EDGAR Filings to a Structured Database using Claude Code
汇智网翻译整理,转载请标明出处