最近在跟着一个NLP的项目,爬取了EDGAR上2021Q1到2022Q2的所有10-Q、10-K和8-K报表并清洗出特定Item的内容。做到现在半个月,总结了大致流程、遇到的问题和解决方法,希望能帮助到有同样需求的朋友们。完整内容大概会拆成3个部分,第一部分先介绍爬取报表的方法。
1. INTRO关于美国证券交易委员会(SEC)的EDGAR系统,请参考:其中包含EDGAR系统的访问权限、访问方法、报表类型等常见问题。由于之后使用的爬取方法不需要自己设置请求间隔,此处仅作了解即可。常用的报表类型包括10-K(annual report)、10-Q(quarterly report)和8-K(current report),具体说明可参考:
SEC.gov | Forms Listhttps://www.sec.gov/forms关于报表的编成,简单来说, EDGAR系统给予每个编写报表的人员一个独特的索引码,称为CIK(central index key),我们查找报表也是基于CIK码而不是公司名称。如果想了解更多EDGAR系统中报表类型及索引问题,可参考论文:
- García, D., & Norli, Ø. (2012). Crawling EDGAR. The spanish review of financial economics, 10(1), 1-10.
每个季度SEC会给出该季度内上传到EDGAR系统的报表的信息,包括CIK、公司名称、编成日期及文件名等等,称为quarterly master index。获取QMI可以帮助我们了解该季度内报表的编成情况,比如对QMI根据CIK进一步筛选来了解某个公司在一段时间内各类报表的编成数量。
很多基于Python、R的packages都能帮助我们获取QMI信息,我使用的是一个近两年新发布的R package,edgar。之后爬取特定时间段内的特定类型的报表也将用到这个包。使用这个包不需要很进阶的爬虫搭建技巧,只要求基本的R语言使用知识,可以说是非常便捷的一个黑箱。该R包与其他更早发布的Python及其他R包的功能对比可以参考原始论文:
- Lonare, G., Patil, B., & Raut, N. (2021). edgar: An R package for the US SEC EDGAR retrieval and parsing of corporate filings. SoftwareX, 16, 100865.
论文中也介绍了部分函数的参数和功能。下文介绍我使用到的部分函数,有其他需求的朋友可自行参考帮助文档(有空的话我会考虑翻译一遍)。
2.1 爬取准备以下内容全部基于R语言。首先安装并导入edgar包:
install.packages('edgar')
library(edgar)
接着设置working directory,之后爬取到的所有内容将默认保存到该wd中。然后是爬虫的常规操作,user agent。该包需要提交的user-agent格式为: 姓名 邮箱,将其作为字符串赋值即可。
setwd("F:/EDGAR")
myid <- 'GOTO Ryusuke niccolologne@gmail.com'
2.2 下载QMI信息
我的任务是下载2021Q1到2022Q2的所有10-K、10-Q及8-K报表,所以需要的QMI为六个季度。在edgar中,我们先使用getMasterIndex函数来下载QMI信息到本地路径:
getMasterIndex(c(2021,2022),myid)
其中第一个参数为想要获取的年份,第二个参数为user-agent。执行操作后会自动创建一个名为“Master Indexes”的文件夹,其中包含指定年份内.idx文件的压缩包及.Rda文件。先导入2021、2022年的.Rda文件:
load("F:/EDGAR/Master Indexes/2021master.Rda")
edgarR3 <- year.master
load("F:/EDGAR/Master Indexes/2022master.Rda")
edgarR4 <- year.master
结果得到edgarR3、edgarR4两个dateframe,具体结构如下图:
可以看到所有信息已经以非常organised的形式包含在这个dataframe里了,我们只要根据需求筛选所需报表的类型、找出对应CIK即可。
以获取6个季度内所有8-K报表信息为例。首先筛选出两年内所有的8-K表格:
ind.R3.8K <- which(edgarR3$form.type=='8-K') ind.R4.8K <- which(edgarR4$form.type=='8-K') f8k <- rbind(edgarR3[ind.R3.8K,],edgarR4[ind.R4.8K,])
接着看看各个季度的8-K报表编成情况:
> nrow(f8k) [1] 98050
可见6个季度内一共有近10万份8-K报表被上传到EDGAR系统中。如果想要知道这些报表来自多少个CIK,可以直接调用f8k中的CIK变量:
> cik.8K <- as.integer(unique(f8k$cik)) > length(cik.8K) [1] 8140
这9.8万份8-K由8140个独特的编写人员编写并上传完成。如果需要进一步查看公司名称、筛选某些公司的8-K报表进行爬取,可以直接对f8k的name变量进行筛选操作。
3. 爬取报表edgar包提供了非常便利的函数来帮助爬取报表,因此我们不需要考虑访问间隔(若自己搭建爬虫而不注意设置间隔,1秒内访问超过10次会导致封IP)和路径等复杂的问题。仍以爬取8-K报表为例,我们使用getFilings函数来获取txt格式的8-K报表。该函数的参数如下:
- cik.no: 由目标公司CIK码组成的整数型向量。若要获取来自所有CIK的报表,则需输入字符串 'ALL';
- form.type: 目标报表类型。与cik,no类似,若要获取所有类型的报表,输入字符串 'ALL';
- filing.year: 由目标年份组成的四位数整数型向量;
- quarter: 由目标季度组成的一位数整数型向量。默认为4个季度。
- downl.permit: 爬取前是否需要二次确认。默认为需要。个人建议最好不要设置为 'False',有时候会莫名其妙的导致爬取无法进行,而且二次确认也不会花费多少时间,只需在给出提示后输入 'y'即可。
- useragent
由于我的任务是所有8-K报表,参数输入如下:
> get.8K <- getFilings('ALL',
+ '8-K',
+ c(2021,2022),
+ useragent = myid)
Total number of filings to be downloaded = 98050. Do you want to download (y/n)?
出现二次确认后输入 'y'即可开始下载。此处将结果返回给get.8K,有助于后期导出统计表格。该函数的返回类型也是一个dataframe,包含以下变量:
同时所有下载好的txt格式的报表也可在wd的 'Edgar filings_full textForm 8-K' 下找到,并且已经按照CIK分好文件夹。老板要求给出一个Excel大表来列出CIK、编成日期、公司名、本地路径及文件名等信息,这个表格也有利于之后提取文本内容并进行清洗,所以又加了以下代码来输出包含所需信息的Excel表格:
exl.8k <- get.8K[,1:4]
names(exl.8k) <- c('CIK','CompanyName','FormType','FilingDate')
FileName <- c()
for (i in 1:nrow(get.8K)) {
main.file <- 'F:/EDGAR/Edgar filings_full text/Form 8-K'
child.file <- get.8K$cik[i]
parent.address <- paste(main.file,child.file, sep = '/')
temp.name <- paste(get.8K$accession.number[i],
'.txt',
sep = '')
full.name <- paste(get.8K$cik[i],
get.8K$form.type[i],
get.8K$date.filed[i],
temp.name,
sep = '_')
local.address <- paste(parent.address,'/',full.name,sep = '')
FileName[i] <- local.address
}
可以查看得到的本地路径向量:
> FileName[1:10] [1] "F:/EDGAR/Edgar filings_full text/Form 8-K/1000045/1000045_8-K_2021-01-25_0001564590-21-002004.txt" [2] "F:/EDGAR/Edgar filings_full text/Form 8-K/1000045/1000045_8-K_2021-02-03_0001564590-21-003940.txt" [3] "F:/EDGAR/Edgar filings_full text/Form 8-K/1000045/1000045_8-K_2021-03-08_0001564590-21-011365.txt" [4] "F:/EDGAR/Edgar filings_full text/Form 8-K/1000045/1000045_8-K_2021-06-02_0001564590-21-031267.txt" [5] "F:/EDGAR/Edgar filings_full text/Form 8-K/1000045/1000045_8-K_2021-06-11_0001564590-21-032560.txt" [6] "F:/EDGAR/Edgar filings_full text/Form 8-K/1000045/1000045_8-K_2021-06-29_0001564590-21-034885.txt" [7] "F:/EDGAR/Edgar filings_full text/Form 8-K/1000045/1000045_8-K_2021-07-30_0001564590-21-039333.txt" [8] "F:/EDGAR/Edgar filings_full text/Form 8-K/1000045/1000045_8-K_2021-09-02_0000950170-21-001640.txt" [9] "F:/EDGAR/Edgar filings_full text/Form 8-K/1000045/1000045_8-K_2021-09-02_0000950170-21-001647.txt" [10] "F:/EDGAR/Edgar filings_full text/Form 8-K/1000045/1000045_8-K_2021-09-30_0000950170-21-001953.txt"
最后将本地路径作为新变量加入exl.8k,并输出为Excel即可:
exl.8k$FileName <- FileName write_xlsx(exl.8k,"2021Q1-2022Q2_8-K_AllFirms(WithLocalAddress).xlsx")
下一部分的内容:
使用Python对10-Q、8-K报表进行初步清洗;获取各个item的起始、结束位置。



